From dc8a8e9beb1a8f5503c03db7a02957e5e4929141 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 3 Apr 2015 17:13:52 +1300 Subject: [PATCH 01/62] Check uses of `Self` in impls in the compiler rather than during expansion Closes #23909 --- src/librustc/middle/astencode.rs | 6 +- src/librustc/middle/def.rs | 12 +- src/librustc_privacy/lib.rs | 2 +- src/librustc_resolve/lib.rs | 177 ++++++++++++----------- src/librustc_trans/save/mod.rs | 2 +- src/librustc_typeck/astconv.rs | 217 +++++++++++++++++++---------- src/librustc_typeck/check/mod.rs | 16 ++- src/librustc_typeck/collect.rs | 17 +-- src/libsyntax/ext/expand.rs | 43 +----- src/test/compile-fail/self-impl.rs | 32 +++++ src/test/run-pass/self-impl.rs | 21 ++- 11 files changed, 326 insertions(+), 219 deletions(-) create mode 100644 src/test/compile-fail/self-impl.rs diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index b6061f39233d2..998ce0cac4700 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -457,7 +457,11 @@ impl tr for def::Def { def::DefMethod(did, p) => { def::DefMethod(did.tr(dcx), p.map(|did2| did2.tr(dcx))) } - def::DefSelfTy(nid) => { def::DefSelfTy(dcx.tr_id(nid)) } + def::DefSelfTy(opt_did, impl_ids) => { def::DefSelfTy(opt_did.map(|did| did.tr(dcx)), + impl_ids.map(|(nid1, nid2)| { + (dcx.tr_id(nid1), + dcx.tr_id(nid2)) + })) } def::DefMod(did) => { def::DefMod(did.tr(dcx)) } def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) } def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) } diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index 6707a4d3fd775..f0b359088549b 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -22,7 +22,8 @@ use std::cell::RefCell; #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Def { DefFn(ast::DefId, bool /* is_ctor */), - DefSelfTy(/* trait id */ ast::NodeId), + DefSelfTy(Option, // trait id + Option<(ast::NodeId, ast::NodeId)>), // (impl id, self type id) DefMod(ast::DefId), DefForeignMod(ast::DefId), DefStatic(ast::DefId, bool /* is_mutbl */), @@ -139,18 +140,19 @@ impl Def { DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) | DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) | DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) | - DefMethod(id, _) | DefConst(id) => { + DefMethod(id, _) | DefConst(id) | DefSelfTy(Some(id), None)=> { id } DefLocal(id) | - DefSelfTy(id) | DefUpvar(id, _) | DefRegion(id) | - DefLabel(id) => { + DefLabel(id) | + DefSelfTy(_, Some((_, id))) => { local_def(id) } - DefPrimTy(_) => panic!("attempted .def_id() on DefPrimTy") + DefPrimTy(_) => panic!("attempted .def_id() on DefPrimTy"), + DefSelfTy(..) => panic!("attempted .def_id() on invalid DefSelfTy"), } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 44ab096281371..060b086ff01e9 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1178,7 +1178,7 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> { let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) { // `int` etc. (None doesn't seem to occur.) None | Some(def::DefPrimTy(..)) => return false, - Some(def) => def.def_id() + Some(def) => def.def_id(), }; // A path can only be private if: // it's in this crate... diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 045320e4fa425..002e5cc5e826d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1689,7 +1689,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } } - DefTyParam(..) | DefSelfTy(_) => { + DefTyParam(..) | DefSelfTy(..) => { for rib in ribs { match rib.kind { NormalRibKind | MethodRibKind | ClosureRibKind(..) => { @@ -1797,63 +1797,57 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } ItemDefaultImpl(_, ref trait_ref) => { - self.with_optional_trait_ref(Some(trait_ref), |_| {}); + self.with_optional_trait_ref(Some(trait_ref), |_, _| {}); } - ItemImpl(_, _, + ItemImpl(_, + _, ref generics, - ref implemented_traits, + ref opt_trait_ref, ref self_type, ref impl_items) => { self.resolve_implementation(generics, - implemented_traits, + opt_trait_ref, &**self_type, + item.id, &impl_items[..]); } ItemTrait(_, ref generics, ref bounds, ref trait_items) => { self.check_if_primitive_type_name(name, item.span); - // Create a new rib for the self type. - let mut self_type_rib = Rib::new(ItemRibKind); - - // plain insert (no renaming, types are not currently hygienic....) - let name = special_names::type_self; - self_type_rib.bindings.insert(name, DlDef(DefSelfTy(item.id))); - self.type_ribs.push(self_type_rib); - - // Create a new rib for the trait-wide type parameters. - self.with_type_parameter_rib(HasTypeParameters(generics, - TypeSpace, - NormalRibKind), - |this| { - this.visit_generics(generics); - visit::walk_ty_param_bounds_helper(this, bounds); - - for trait_item in trait_items { - // Create a new rib for the trait_item-specific type - // parameters. - // - // FIXME #4951: Do we need a node ID here? - - let type_parameters = match trait_item.node { - ast::MethodTraitItem(ref sig, _) => { - HasTypeParameters(&sig.generics, - FnSpace, - MethodRibKind) - } - ast::TypeTraitItem(..) => { - this.check_if_primitive_type_name(trait_item.ident.name, - trait_item.span); - NoTypeParameters - } - }; - this.with_type_parameter_rib(type_parameters, |this| { - visit::walk_trait_item(this, trait_item) - }); - } + self.with_self_rib(DefSelfTy(Some(local_def(item.id)), None), |this| { + // Create a new rib for the trait-wide type parameters. + this.with_type_parameter_rib(HasTypeParameters(generics, + TypeSpace, + NormalRibKind), + |this| { + this.visit_generics(generics); + visit::walk_ty_param_bounds_helper(this, bounds); + + for trait_item in trait_items { + // Create a new rib for the trait_item-specific type + // parameters. + // + // FIXME #4951: Do we need a node ID here? + + let type_parameters = match trait_item.node { + ast::MethodTraitItem(ref sig, _) => { + HasTypeParameters(&sig.generics, + FnSpace, + MethodRibKind) + } + ast::TypeTraitItem(..) => { + this.check_if_primitive_type_name(trait_item.ident.name, + trait_item.span); + NoTypeParameters + } + }; + this.with_type_parameter_rib(type_parameters, |this| { + visit::walk_trait_item(this, trait_item) + }); + } + }); }); - - self.type_ribs.pop(); } ItemMod(_) | ItemForeignMod(_) => { @@ -2030,8 +2024,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { visit::walk_generics(self, generics); } - fn with_current_self_type(&mut self, self_type: &Ty, f: F) -> T where - F: FnOnce(&mut Resolver) -> T, + fn with_current_self_type(&mut self, self_type: &Ty, f: F) -> T + where F: FnOnce(&mut Resolver) -> T { // Handle nested impls (inside fn bodies) let previous_value = replace(&mut self.current_self_type, Some(self_type.clone())); @@ -2044,29 +2038,44 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { opt_trait_ref: Option<&TraitRef>, f: F) -> T - where F: FnOnce(&mut Resolver) -> T, + where F: FnOnce(&mut Resolver, Option) -> T { let mut new_val = None; + let mut new_id = None; if let Some(trait_ref) = opt_trait_ref { - match self.resolve_trait_reference(trait_ref.ref_id, &trait_ref.path, 0) { - Ok(path_res) => { - self.record_def(trait_ref.ref_id, path_res); - new_val = Some((path_res.base_def.def_id(), trait_ref.clone())); - } - Err(_) => { /* error was already reported */ } + if let Ok(path_res) = self.resolve_trait_reference(trait_ref.ref_id, + &trait_ref.path, 0) { + assert!(path_res.depth == 0); + self.record_def(trait_ref.ref_id, path_res); + new_val = Some((path_res.base_def.def_id(), trait_ref.clone())); + new_id = Some(path_res.base_def.def_id()); } visit::walk_trait_ref(self, trait_ref); } let original_trait_ref = replace(&mut self.current_trait_ref, new_val); - let result = f(self); + let result = f(self, new_id); self.current_trait_ref = original_trait_ref; result } + fn with_self_rib(&mut self, self_def: Def, f: F) + where F: FnOnce(&mut Resolver) + { + let mut self_type_rib = Rib::new(NormalRibKind); + + // plain insert (no renaming, types are not currently hygienic....) + let name = special_names::type_self; + self_type_rib.bindings.insert(name, DlDef(self_def)); + self.type_ribs.push(self_type_rib); + f(self); + self.type_ribs.pop(); + } + fn resolve_implementation(&mut self, generics: &Generics, opt_trait_reference: &Option, self_type: &Ty, + item_id: NodeId, impl_items: &[P]) { // If applicable, create a rib for the type parameters. self.with_type_parameter_rib(HasTypeParameters(generics, @@ -2077,40 +2086,42 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { this.visit_generics(generics); // Resolve the trait reference, if necessary. - this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this| { + this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| { // Resolve the self type. this.visit_ty(self_type); - this.with_current_self_type(self_type, |this| { - for impl_item in impl_items { - match impl_item.node { - MethodImplItem(ref sig, _) => { - // If this is a trait impl, ensure the method - // exists in trait - this.check_trait_item(impl_item.ident.name, - impl_item.span); - - // We also need a new scope for the method- - // specific type parameters. - let type_parameters = - HasTypeParameters(&sig.generics, - FnSpace, - MethodRibKind); - this.with_type_parameter_rib(type_parameters, |this| { - visit::walk_impl_item(this, impl_item); - }); - } - TypeImplItem(ref ty) => { - // If this is a trait impl, ensure the method - // exists in trait - this.check_trait_item(impl_item.ident.name, - impl_item.span); + this.with_self_rib(DefSelfTy(trait_id, Some((item_id, self_type.id))), |this| { + this.with_current_self_type(self_type, |this| { + for impl_item in impl_items { + match impl_item.node { + MethodImplItem(ref sig, _) => { + // If this is a trait impl, ensure the method + // exists in trait + this.check_trait_item(impl_item.ident.name, + impl_item.span); + + // We also need a new scope for the method- + // specific type parameters. + let type_parameters = + HasTypeParameters(&sig.generics, + FnSpace, + MethodRibKind); + this.with_type_parameter_rib(type_parameters, |this| { + visit::walk_impl_item(this, impl_item); + }); + } + TypeImplItem(ref ty) => { + // If this is a trait impl, ensure the method + // exists in trait + this.check_trait_item(impl_item.ident.name, + impl_item.span); - this.visit_ty(ty); + this.visit_ty(ty); + } + ast::MacImplItem(_) => {} } - ast::MacImplItem(_) => {} } - } + }); }); }); }); diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 26fcf947e4f90..691276a8eb1b3 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -248,7 +248,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { def::DefFn(..) => Some(recorder::FnRef), - def::DefSelfTy(_) | + def::DefSelfTy(..) | def::DefRegion(_) | def::DefLabel(_) | def::DefTyParam(..) | diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 939142cff1c32..1e7e27762f67c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -56,7 +56,7 @@ use middle::privacy::{AllPublic, LastMod}; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::traits; use middle::ty::{self, RegionEscape, Ty}; -use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, +use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::ppaux::{self, Repr, UserString}; @@ -1041,53 +1041,30 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt, type_str, trait_str, name); } -// Create a type from a a path to an associated type. -// For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C -// and item_segment is the path segment for D. We return a type and a def for -// the whole path. -// Will fail except for T::A and Self::A; i.e., if ty/ty_path_def are not a type -// parameter or Self. -fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, - span: Span, - ty: Ty<'tcx>, +// Search for a bound on a type parameter which includes the associated item +// given by assoc_name. We assume that ty_path_def is the def for such a type +// parameter (which might be `Self`). This function will fail if there are no +// suitable bounds or there is any ambiguity. +fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, ty_path_def: def::Def, - item_segment: &ast::PathSegment) - -> (Ty<'tcx>, def::Def) + assoc_name: ast::Name, + span: Span) + -> Result, ErrorReported> { let tcx = this.tcx(); - let assoc_name = item_segment.identifier.name; - - debug!("associated_path_def_to_ty: {}::{}", ty.repr(tcx), token::get_name(assoc_name)); - - check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); - - // Check that the path prefix given by ty/ty_path_def is a type parameter/Self. - match (&ty.sty, ty_path_def) { - (&ty::ty_param(_), def::DefTyParam(..)) | - (&ty::ty_param(_), def::DefSelfTy(_)) => {} - _ => { - report_ambiguous_associated_type(tcx, - span, - &ty.user_string(tcx), - "Trait", - &token::get_name(assoc_name)); - return (tcx.types.err, ty_path_def); - } - } let ty_param_node_id = ty_path_def.local_node_id(); - let ty_param_name = tcx.ty_param_defs.borrow().get(&ty_param_node_id).unwrap().name; let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) { Ok(v) => v, Err(ErrorReported) => { - return (tcx.types.err, ty_path_def); + return Err(ErrorReported); } }; // Ensure the super predicates and stop if we encountered an error. if bounds.iter().any(|b| this.ensure_super_predicates(span, b.def_id()).is_err()) { - return (this.tcx().types.err, ty_path_def); + return Err(ErrorReported); } // Check that there is exactly one way to find an associated type with the @@ -1097,12 +1074,13 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name)) .collect(); + let ty_param_name = tcx.ty_param_defs.borrow().get(&ty_param_node_id).unwrap().name; if suitable_bounds.len() == 0 { span_err!(tcx.sess, span, E0220, "associated type `{}` not found for type parameter `{}`", token::get_name(assoc_name), token::get_name(ty_param_name)); - return (this.tcx().types.err, ty_path_def); + return Err(ErrorReported); } if suitable_bounds.len() > 1 { @@ -1112,22 +1090,87 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, token::get_name(ty_param_name)); for suitable_bound in &suitable_bounds { - span_note!(this.tcx().sess, span, + span_note!(tcx.sess, span, "associated type `{}` could derive from `{}`", token::get_name(ty_param_name), - suitable_bound.user_string(this.tcx())); + suitable_bound.user_string(tcx)); } } - let suitable_bound = suitable_bounds.pop().unwrap().clone(); - let trait_did = suitable_bound.0.def_id; + Ok(suitable_bounds.pop().unwrap().clone()) +} + +// Create a type from a a path to an associated type. +// For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C +// and item_segment is the path segment for D. We return a type and a def for +// the whole path. +// Will fail except for T::A and Self::A; i.e., if ty/ty_path_def are not a type +// parameter or Self. +fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, + span: Span, + ty: Ty<'tcx>, + ty_path_def: def::Def, + item_segment: &ast::PathSegment) + -> (Ty<'tcx>, def::Def) +{ + let tcx = this.tcx(); + let assoc_name = item_segment.identifier.name; + + debug!("associated_path_def_to_ty: {}::{}", ty.repr(tcx), token::get_name(assoc_name)); + + check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); - let ty = this.projected_ty_from_poly_trait_ref(span, suitable_bound, assoc_name); + // Find the type of the associated item, and the trait where the associated + // item is declared. + let (ty, trait_did) = match (&ty.sty, ty_path_def) { + (_, def::DefSelfTy(Some(trait_did), Some((impl_id, _)))) => { + // `Self` in an impl of a trait - we have a concrete self type and a + // trait reference. + match tcx.map.expect_item(impl_id).node { + ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) => { + let trait_segment = &trait_ref.path.segments.last().unwrap(); + let trait_ref = ast_path_to_mono_trait_ref(this, + &ExplicitRscope, + span, + PathParamMode::Explicit, + trait_did, + Some(ty), + trait_segment); + + let ty = this.projected_ty(span, trait_ref, assoc_name); + (ty, trait_did) + } + _ => unreachable!() + } + } + (&ty::ty_param(_), def::DefTyParam(..)) | + (&ty::ty_param(_), def::DefSelfTy(Some(_), None)) => { + // A type parameter or Self, we need to find the associated item from + // a bound. + let bound = match find_bound_for_assoc_item(this, ty_path_def, assoc_name, span) { + Ok(bound) => bound, + Err(ErrorReported) => return (tcx.types.err, ty_path_def), + }; + let trait_did = bound.0.def_id; + let ty = this.projected_ty_from_poly_trait_ref(span, bound, assoc_name); + + (ty, trait_did) + } + _ => { + println!("{:?} {:?}", ty.sty, ty_path_def); + report_ambiguous_associated_type(tcx, + span, + &ty.user_string(tcx), + "Trait", + &token::get_name(assoc_name)); + return (tcx.types.err, ty_path_def); + } + }; let item_did = if trait_did.krate == ast::LOCAL_CRATE { // `ty::trait_items` used below requires information generated // by type collection, which may be in progress at this point. - match this.tcx().map.expect_item(trait_did.node).node { + match tcx.map.expect_item(trait_did.node).node { ast::ItemTrait(_, _, _, ref trait_items) => { let item = trait_items.iter() .find(|i| i.ident.name == assoc_name) @@ -1137,7 +1180,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, _ => unreachable!() } } else { - let trait_items = ty::trait_items(this.tcx(), trait_did); + let trait_items = ty::trait_items(tcx, trait_did); let item = trait_items.iter().find(|i| i.name() == assoc_name); item.expect("missing associated type").def_id() }; @@ -1173,14 +1216,13 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx)); - let trait_ref = - ast_path_to_mono_trait_ref(this, - rscope, - span, - param_mode, - trait_def_id, - Some(self_ty), - trait_segment); + let trait_ref = ast_path_to_mono_trait_ref(this, + rscope, + span, + param_mode, + trait_def_id, + Some(self_ty), + trait_segment); debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx)); @@ -1220,20 +1262,20 @@ pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>, } } -// Note that both base_segments and assoc_segments may be empty, although not at -// the same time. -pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, - rscope: &RegionScope, - span: Span, - param_mode: PathParamMode, - def: &def::Def, - opt_self_ty: Option>, - base_segments: &[ast::PathSegment], - assoc_segments: &[ast::PathSegment]) - -> Ty<'tcx> { +// Check the base def in a PathResolution and convert it to a Ty. If there are +// associated types in the PathResolution, these will need to be seperately +// resolved. +fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + def: &def::Def, + opt_self_ty: Option>, + base_segments: &[ast::PathSegment]) + -> Ty<'tcx> { let tcx = this.tcx(); - let base_ty = match *def { + match *def { def::DefTrait(trait_def_id) => { // N.B. this case overlaps somewhat with // TyObjectSum, see that fn for details @@ -1257,18 +1299,28 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, } def::DefTy(did, _) | def::DefStruct(did) => { check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS); - ast_path_to_ty(this, rscope, span, - param_mode, did, + ast_path_to_ty(this, + rscope, + span, + param_mode, + did, base_segments.last().unwrap()) } def::DefTyParam(space, index, _, name) => { check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); ty::mk_param(tcx, space, index, name) } - def::DefSelfTy(_) => { - // N.b.: resolve guarantees that the this type only appears in a - // trait, which we rely upon in various places when creating - // substs. + def::DefSelfTy(_, Some((_, self_ty_id))) => { + // Self in impl (we know the concrete type). + check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); + if let Some(&ty) = tcx.ast_ty_to_ty_cache.borrow().get(&self_ty_id) { + ty + } else { + tcx.sess.span_bug(span, "self type has not been fully resolved") + } + } + def::DefSelfTy(Some(_), None) => { + // Self in trait. check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); ty::mk_self_type(tcx) } @@ -1288,6 +1340,9 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, // FIXME(#22519) This part of the resolution logic should be // avoided entirely for that form, once we stop needed a Def // for `associated_path_def_to_ty`. + // Fixing this will also let use resolve ::Foo the same way we + // resolve Self::Foo, at the moment we can't resolve the former because + // we don't have the trait information around, which is just sad. if !base_segments.is_empty() { span_err!(tcx.sess, @@ -1308,11 +1363,29 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, "found value name used as a type: {:?}", *def); return this.tcx().types.err; } - }; + } +} - // If any associated type segments remain, attempt to resolve them. - let mut ty = base_ty; +// Note that both base_segments and assoc_segments may be empty, although not at +// the same time. +pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + def: &def::Def, + opt_self_ty: Option>, + base_segments: &[ast::PathSegment], + assoc_segments: &[ast::PathSegment]) + -> Ty<'tcx> { + let mut ty = base_def_to_ty(this, + rscope, + span, + param_mode, + def, + opt_self_ty, + base_segments); let mut def = *def; + // If any associated type segments remain, attempt to resolve them. for segment in assoc_segments { if ty.sty == ty::ty_err { break; @@ -1996,7 +2069,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, check_type_argument_count(tcx, b.trait_ref.path.span, parameters.types().len(), 0, 0); } - if parameters.lifetimes().len() > 0{ + if parameters.lifetimes().len() > 0 { report_lifetime_number_error(tcx, b.trait_ref.path.span, parameters.lifetimes().len(), 0); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 156fbfede9c98..ce1227608cf31 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3341,11 +3341,17 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let def = path_res.base_def; if path_res.depth == 0 { - let (scheme, predicates) = - type_scheme_and_predicates_for_def(fcx, expr.span, def); - instantiate_path(fcx, &path.segments, - scheme, &predicates, - opt_self_ty, def, expr.span, id); + let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, + expr.span, + def); + instantiate_path(fcx, + &path.segments, + scheme, + &predicates, + opt_self_ty, + def, + expr.span, + id); } else { let ty_segments = path.segments.init(); let base_ty_end = path.segments.len() - path_res.depth; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8f1b8bf109215..f38ebf111fd3f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -547,14 +547,15 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>, if let ast::TyPath(None, _) = ast_ty.node { let path_res = *tcx.def_map.borrow().get(&ast_ty.id).unwrap(); match path_res.base_def { - def::DefSelfTy(node_id) => - path_res.depth == 0 && node_id == param_id, - - def::DefTyParam(_, _, def_id, _) => - path_res.depth == 0 && def_id == local_def(param_id), - - _ => - false, + def::DefSelfTy(Some(def_id), None) => { + path_res.depth == 0 && def_id.node == param_id + } + def::DefTyParam(_, _, def_id, _) => { + path_res.depth == 0 && def_id == local_def(param_id) + } + _ => { + false + } } } else { false diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 94abc0b34bc62..b71c23b29e38a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -14,7 +14,6 @@ use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac}; use ast::{StmtExpr, StmtSemi}; use ast::TokenTree; use ast; -use ast_util::path_to_ident; use ext::mtwt; use ext::build::AstBuilder; use attr; @@ -34,30 +33,6 @@ use visit; use visit::Visitor; use std_inject; -pub fn expand_type(t: P, - fld: &mut MacroExpander, - impl_ty: Option>) - -> P { - debug!("expanding type {:?} with impl_ty {:?}", t, impl_ty); - let t = match (t.node.clone(), impl_ty) { - // Expand uses of `Self` in impls to the concrete type. - (ast::Ty_::TyPath(None, ref path), Some(ref impl_ty)) => { - let path_as_ident = path_to_ident(path); - // Note unhygenic comparison here. I think this is correct, since - // even though `Self` is almost just a type parameter, the treatment - // for this expansion is as if it were a keyword. - if path_as_ident.is_some() && - path_as_ident.unwrap().name == token::special_idents::type_self.name { - impl_ty.clone() - } else { - t - } - } - _ => t - }; - fold::noop_fold_ty(t, fld) -} - pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { e.and_then(|ast::Expr {id, node, span}| match node { // expr_mac should really be expr_ext or something; it's the @@ -1354,13 +1329,11 @@ fn expand_and_rename_method(sig: ast::MethodSig, body: P, /// A tree-folder that performs macro expansion pub struct MacroExpander<'a, 'b:'a> { pub cx: &'a mut ExtCtxt<'b>, - // The type of the impl currently being expanded. - current_impl_type: Option>, } impl<'a, 'b> MacroExpander<'a, 'b> { pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> { - MacroExpander { cx: cx, current_impl_type: None } + MacroExpander { cx: cx } } } @@ -1374,14 +1347,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { } fn fold_item(&mut self, item: P) -> SmallVector> { - let prev_type = self.current_impl_type.clone(); - if let ast::Item_::ItemImpl(_, _, _, _, ref ty, _) = item.node { - self.current_impl_type = Some(ty.clone()); - } - - let result = expand_item(item, self); - self.current_impl_type = prev_type; - result + expand_item(item, self) } fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ { @@ -1410,11 +1376,6 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { .into_iter().map(|i| i.expect_impl_item()).collect() } - fn fold_ty(&mut self, t: P) -> P { - let impl_type = self.current_impl_type.clone(); - expand_type(t, self, impl_type) - } - fn new_span(&mut self, span: Span) -> Span { new_span(self.cx, span) } diff --git a/src/test/compile-fail/self-impl.rs b/src/test/compile-fail/self-impl.rs new file mode 100644 index 0000000000000..ec913aa844dbd --- /dev/null +++ b/src/test/compile-fail/self-impl.rs @@ -0,0 +1,32 @@ +// 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. + +// Test that unsupported uses of `Self` in impls don't crash + +struct Bar; + +trait Foo { + type Baz; +} + +impl Foo for Bar { + type Baz = bool; +} + +impl Bar { + fn f() { + let _: ::Baz = true; +//~^ERROR: ambiguous associated type; specify the type using the syntax `::Baz` + let _: Self::Baz = true; +//~^ERROR: ambiguous associated type; specify the type using the syntax `::Baz` + } +} + +fn main() {} diff --git a/src/test/run-pass/self-impl.rs b/src/test/run-pass/self-impl.rs index c32773aa88c2a..746ddc9892abe 100644 --- a/src/test/run-pass/self-impl.rs +++ b/src/test/run-pass/self-impl.rs @@ -22,6 +22,17 @@ impl Foo { fn foo(_x: Self, _y: &Self, _z: Box) -> Self { Foo } + + fn baz() { + // Test that Self cannot be shadowed. + type Foo = i32; + // There is no empty method on i32. + Self::empty(); + + let _: Self = Foo; + } + + fn empty() {} } // Test uses when implementing a trait and with a type parameter. @@ -30,12 +41,18 @@ pub struct Baz { } trait Bar { + type Qux; + fn bar(x: Self, y: &Self, z: Box) -> Self; fn dummy(&self, x: X) { } } impl Bar for Box> { + type Qux = i32; + fn bar(_x: Self, _y: &Self, _z: Box) -> Self { + let _: Self::Qux = 42; + let _: >::Qux = 42; box Baz { f: 42 } } } @@ -43,6 +60,6 @@ impl Bar for Box> { fn main() { let _: Foo = Foo::foo(Foo, &Foo, box Foo); let _: Box> = Bar::bar(box Baz { f: 42 }, - &box Baz { f: 42 }, - box box Baz { f: 42 }); + &box Baz { f: 42 }, + box box Baz { f: 42 }); } From 05b8a106e45b0c8381c6bc89e76e7bb94b03a84c Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 3 Apr 2015 19:50:32 +0200 Subject: [PATCH 02/62] Encode more precise scoping rules for function params. Function params which outlive everything in the body (incl temporaries). Thus if we assign them their own `CodeExtent`, the region inference can properly show that it is sound to have temporaries with destructors that reference the parameters (because such temporaries will be dropped before the parameters are). This allows us to address issue 23338 in a clean way. As a drive-by, fix a mistake in the tyencode for `CodeExtent::BlockRemainder`. --- src/librustc/metadata/tydecode.rs | 13 +++++++++++ src/librustc/metadata/tyencode.rs | 4 +++- src/librustc/middle/region.rs | 39 ++++++++++++++++++++++++++----- src/librustc/util/ppaux.rs | 5 ++++ 4 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 3fb128b1881f5..8030275ef303a 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -373,6 +373,16 @@ fn parse_region_(st: &mut PState, conv: &mut F) -> ty::Region where fn parse_scope(st: &mut PState) -> region::CodeExtent { match next(st) { + 'P' => { + assert_eq!(next(st), '['); + let fn_id = parse_uint(st) as ast::NodeId; + assert_eq!(next(st), '|'); + let body_id = parse_uint(st) as ast::NodeId; + assert_eq!(next(st), ']'); + region::CodeExtent::ParameterScope { + fn_id: fn_id, body_id: body_id + } + } 'M' => { let node_id = parse_uint(st) as ast::NodeId; region::CodeExtent::Misc(node_id) @@ -382,8 +392,11 @@ fn parse_scope(st: &mut PState) -> region::CodeExtent { region::CodeExtent::DestructionScope(node_id) } 'B' => { + assert_eq!(next(st), '['); let node_id = parse_uint(st) as ast::NodeId; + assert_eq!(next(st), '|'); let first_stmt_index = parse_uint(st); + assert_eq!(next(st), ']'); let block_remainder = region::BlockRemainder { block: node_id, first_statement_index: first_stmt_index, }; diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 7a2df4966283a..90a905f184071 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -275,9 +275,11 @@ pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) { fn enc_scope(w: &mut Encoder, _cx: &ctxt, scope: region::CodeExtent) { match scope { + region::CodeExtent::ParameterScope { + fn_id, body_id } => mywrite!(w, "P[{}|{}]", fn_id, body_id), region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id), region::CodeExtent::Remainder(region::BlockRemainder { - block: b, first_statement_index: i }) => mywrite!(w, "B{}{}", b, i), + block: b, first_statement_index: i }) => mywrite!(w, "B[{}|{}]", b, i), region::CodeExtent::DestructionScope(node_id) => mywrite!(w, "D{}", node_id), } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 652f661325206..727a1dcdfb31e 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -95,7 +95,15 @@ use syntax::visit::{Visitor, FnKind}; RustcDecodable, Debug, Copy)] pub enum CodeExtent { Misc(ast::NodeId), - DestructionScope(ast::NodeId), // extent of destructors for temporaries of node-id + + // extent of parameters passed to a function or closure (they + // outlive its body) + ParameterScope { fn_id: ast::NodeId, body_id: ast::NodeId }, + + // extent of destructors for temporaries of node-id + DestructionScope(ast::NodeId), + + // extent of code following a `let id = expr;` binding in a block Remainder(BlockRemainder) } @@ -153,15 +161,19 @@ impl CodeExtent { pub fn node_id(&self) -> ast::NodeId { match *self { CodeExtent::Misc(node_id) => node_id, + + // These cases all return rough approximations to the + // precise extent denoted by `self`. CodeExtent::Remainder(br) => br.block, CodeExtent::DestructionScope(node_id) => node_id, + CodeExtent::ParameterScope { fn_id: _, body_id } => body_id, } } /// Maps this scope to a potentially new one according to the /// NodeId transformer `f_id`. pub fn map_id(&self, f_id: F) -> CodeExtent where - F: FnOnce(ast::NodeId) -> ast::NodeId, + F: Fn(ast::NodeId) -> ast::NodeId, { match *self { CodeExtent::Misc(node_id) => CodeExtent::Misc(f_id(node_id)), @@ -170,6 +182,8 @@ impl CodeExtent { block: f_id(br.block), first_statement_index: br.first_statement_index }), CodeExtent::DestructionScope(node_id) => CodeExtent::DestructionScope(f_id(node_id)), + CodeExtent::ParameterScope { fn_id, body_id } => + CodeExtent::ParameterScope { fn_id: f_id(fn_id), body_id: f_id(body_id) }, } } @@ -180,6 +194,7 @@ impl CodeExtent { match ast_map.find(self.node_id()) { Some(ast_map::NodeBlock(ref blk)) => { match *self { + CodeExtent::ParameterScope { .. } | CodeExtent::Misc(_) | CodeExtent::DestructionScope(_) => Some(blk.span), @@ -277,6 +292,7 @@ enum InnermostDeclaringBlock { Block(ast::NodeId), Statement(DeclaringStatementContext), Match(ast::NodeId), + FnDecl { fn_id: ast::NodeId, body_id: ast::NodeId }, } impl InnermostDeclaringBlock { @@ -285,6 +301,8 @@ impl InnermostDeclaringBlock { InnermostDeclaringBlock::None => { return Option::None; } + InnermostDeclaringBlock::FnDecl { fn_id, body_id } => + CodeExtent::ParameterScope { fn_id: fn_id, body_id: body_id }, InnermostDeclaringBlock::Block(id) | InnermostDeclaringBlock::Match(id) => CodeExtent::from_node_id(id), InnermostDeclaringBlock::Statement(s) => s.to_code_extent(), @@ -1198,13 +1216,20 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, body.id, visitor.cx.parent); + // This scope covers the function body, which includes the + // bindings introduced by let statements as well as temporaries + // created by the fn's tail expression (if any). It does *not* + // include the fn parameters (see below). let body_scope = CodeExtent::from_node_id(body.id); visitor.region_maps.mark_as_terminating_scope(body_scope); let dtor_scope = CodeExtent::DestructionScope(body.id); visitor.region_maps.record_encl_scope(body_scope, dtor_scope); - record_superlifetime(visitor, dtor_scope, body.span); + let fn_decl_scope = CodeExtent::ParameterScope { fn_id: id, body_id: body.id }; + visitor.region_maps.record_encl_scope(dtor_scope, fn_decl_scope); + + record_superlifetime(visitor, fn_decl_scope, body.span); if let Some(root_id) = visitor.cx.root_id { visitor.region_maps.record_fn_parent(body.id, root_id); @@ -1212,11 +1237,13 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, let outer_cx = visitor.cx; - // The arguments and `self` are parented to the body of the fn. + // The arguments and `self` are parented to the fn. visitor.cx = Context { root_id: Some(body.id), - parent: InnermostEnclosingExpr::Some(body.id), - var_parent: InnermostDeclaringBlock::Block(body.id) + parent: InnermostEnclosingExpr::None, + var_parent: InnermostDeclaringBlock::FnDecl { + fn_id: id, body_id: body.id + }, }; visit::walk_fn_decl(visitor, decl); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 60b422b3769d5..7358b4cc0f6ec 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -113,6 +113,9 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) }; let scope_decorated_tag = match scope { region::CodeExtent::Misc(_) => tag, + region::CodeExtent::ParameterScope { .. } => { + "scope of parameters for function" + } region::CodeExtent::DestructionScope(_) => { new_string = format!("destruction scope surrounding {}", tag); &*new_string @@ -952,6 +955,8 @@ impl<'tcx> Repr<'tcx> for ty::FreeRegion { impl<'tcx> Repr<'tcx> for region::CodeExtent { fn repr(&self, _tcx: &ctxt) -> String { match *self { + region::CodeExtent::ParameterScope { fn_id, body_id } => + format!("ParameterScope({}, {})", fn_id, body_id), region::CodeExtent::Misc(node_id) => format!("Misc({})", node_id), region::CodeExtent::DestructionScope(node_id) => From c4216a50bd9662fd5e60946643c718ac0325d75f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 3 Apr 2015 20:09:04 +0200 Subject: [PATCH 03/62] Test cases for Issue 23338. We ignore pretty for the params-outlive-temps-of-body test because the way its comments are formatted exercises a known bug in the pretty printer. --- ...e-23338-locals-die-before-temps-of-body.rs | 36 ++++ .../issue-23338-ensure-param-drop-order.rs | 171 ++++++++++++++++++ ...ssue-23338-params-outlive-temps-of-body.rs | 39 ++++ 3 files changed, 246 insertions(+) create mode 100644 src/test/compile-fail/issue-23338-locals-die-before-temps-of-body.rs create mode 100644 src/test/run-pass/issue-23338-ensure-param-drop-order.rs create mode 100644 src/test/run-pass/issue-23338-params-outlive-temps-of-body.rs diff --git a/src/test/compile-fail/issue-23338-locals-die-before-temps-of-body.rs b/src/test/compile-fail/issue-23338-locals-die-before-temps-of-body.rs new file mode 100644 index 0000000000000..993893438e536 --- /dev/null +++ b/src/test/compile-fail/issue-23338-locals-die-before-temps-of-body.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. + +// This is just checking that we still reject code where temp values +// are borrowing values for longer than they will be around. +// +// Compare to run-pass/issue-23338-params-outlive-temps-of-body.rs + +use std::cell::RefCell; + +fn foo(x: RefCell) -> String { + let y = x; + y.borrow().clone() //~ ERROR `y` does not live long enough +} + +fn foo2(x: RefCell) -> String { + let ret = { + let y = x; + y.borrow().clone() //~ ERROR `y` does not live long enough + }; + ret +} + +fn main() { + let r = RefCell::new(format!("data")); + assert_eq!(foo(r), "data"); + let r = RefCell::new(format!("data")); + assert_eq!(foo2(r), "data"); +} diff --git a/src/test/run-pass/issue-23338-ensure-param-drop-order.rs b/src/test/run-pass/issue-23338-ensure-param-drop-order.rs new file mode 100644 index 0000000000000..0815ff084fb51 --- /dev/null +++ b/src/test/run-pass/issue-23338-ensure-param-drop-order.rs @@ -0,0 +1,171 @@ +// 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. + +// ignore-pretty : (#23623) problems when ending with // comments + +// This test is ensuring that parameters are indeed dropped after +// temporaries in a fn body. + +use std::cell::RefCell; + +use self::d::D; + +pub fn main() { + let log = RefCell::new(vec![]); + d::println(&format!("created empty log")); + test(&log); + + assert_eq!(&log.borrow()[..], + [ + // created empty log + // +-- Make D(da_0, 0) + // | +-- Make D(de_1, 1) + // | | calling foo + // | | entered foo + // | | +-- Make D(de_2, 2) + // | | | +-- Make D(da_1, 3) + // | | | | +-- Make D(de_3, 4) + // | | | | | +-- Make D(de_4, 5) + 3, // | | | +-- Drop D(da_1, 3) + // | | | | | + 4, // | | | +-- Drop D(de_3, 4) + // | | | | + // | | | | eval tail of foo + // | | | +-- Make D(de_5, 6) + // | | | | +-- Make D(de_6, 7) + 6, // | | | +-- Drop D(de_5, 6) + // | | | | | + 5, // | | | | +-- Drop D(de_4, 5) + // | | | | + 2, // | | +-- Drop D(de_2, 2) + // | | | + 1, // | +-- Drop D(de_1, 1) + // | | + 0, // +-- Drop D(da_0, 0) + // | + // | result D(de_6, 7) + 7 // +-- Drop D(de_6, 7) + + ]); +} + +fn test<'a>(log: d::Log<'a>) { + let da = D::new("da", 0, log); + let de = D::new("de", 1, log); + d::println(&format!("calling foo")); + let result = foo(da, de); + d::println(&format!("result {}", result)); +} + +fn foo<'a>(da0: D<'a>, de1: D<'a>) -> D<'a> { + d::println(&format!("entered foo")); + let de2 = de1.incr(); // creates D(de_2, 2) + let de4 = { + let _da1 = da0.incr(); // creates D(da_1, 3) + de2.incr().incr() // creates D(de_3, 4) and D(de_4, 5) + }; + d::println(&format!("eval tail of foo")); + de4.incr().incr() // creates D(de_5, 6) and D(de_6, 7) +} + +// This module provides simultaneous printouts of the dynamic extents +// of all of the D values, in addition to logging the order that each +// is dropped. + +const PREF_INDENT: u32 = 16; + +pub mod d { + #![allow(unused_parens)] + use std::fmt; + use std::mem; + use std::cell::RefCell; + + static mut counter: u32 = 0; + static mut trails: u64 = 0; + + pub type Log<'a> = &'a RefCell>; + + pub fn current_width() -> u32 { + unsafe { max_width() - trails.leading_zeros() } + } + + pub fn max_width() -> u32 { + unsafe { + (mem::size_of_val(&trails)*8) as u32 + } + } + + pub fn indent_println(my_trails: u32, s: &str) { + let mut indent: String = String::new(); + for i in 0..my_trails { + unsafe { + if trails & (1 << i) != 0 { + indent = indent + "| "; + } else { + indent = indent + " "; + } + } + } + println!("{}{}", indent, s); + } + + pub fn println(s: &str) { + indent_println(super::PREF_INDENT, s); + } + + fn first_avail() -> u32 { + unsafe { + for i in 0..64 { + if trails & (1 << i) == 0 { + return i; + } + } + } + panic!("exhausted trails"); + } + + pub struct D<'a> { + name: &'static str, i: u32, uid: u32, trail: u32, log: Log<'a> + } + + impl<'a> fmt::Display for D<'a> { + fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { + write!(w, "D({}_{}, {})", self.name, self.i, self.uid) + } + } + + impl<'a> D<'a> { + pub fn new(name: &'static str, i: u32, log: Log<'a>) -> D<'a> { + unsafe { + let trail = first_avail(); + let ctr = counter; + counter += 1; + trails |= (1 << trail); + let ret = D { + name: name, i: i, log: log, uid: ctr, trail: trail + }; + indent_println(trail, &format!("+-- Make {}", ret)); + ret + } + } + pub fn incr(&self) -> D<'a> { + D::new(self.name, self.i + 1, self.log) + } + } + + impl<'a> Drop for D<'a> { + fn drop(&mut self) { + unsafe { trails &= !(1 << self.trail); }; + self.log.borrow_mut().push(self.uid); + indent_println(self.trail, &format!("+-- Drop {}", self)); + indent_println(::PREF_INDENT, ""); + } + } +} diff --git a/src/test/run-pass/issue-23338-params-outlive-temps-of-body.rs b/src/test/run-pass/issue-23338-params-outlive-temps-of-body.rs new file mode 100644 index 0000000000000..cb9e852e52692 --- /dev/null +++ b/src/test/run-pass/issue-23338-params-outlive-temps-of-body.rs @@ -0,0 +1,39 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is largely checking that we now accept code where temp values +// are borrowing from the input parameters (the `foo` case below). +// +// Compare to run-pass/issue-23338-params-outlive-temps-of-body.rs +// +// (The `foo2` case is just for parity with the above test, which +// shows what happens when you move the `y`-binding to the inside of +// the inner block.) + +use std::cell::RefCell; + +fn foo(x: RefCell) -> String { + x.borrow().clone() +} + +fn foo2(x: RefCell) -> String { + let y = x; + let ret = { + y.borrow().clone() + }; + ret +} + +pub fn main() { + let r = RefCell::new(format!("data")); + assert_eq!(foo(r), "data"); + let r = RefCell::new(format!("data")); + assert_eq!(foo2(r), "data"); +} From 19e9828fb8f87c51175f638461a5b4051d022158 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Sat, 4 Apr 2015 12:37:25 -0700 Subject: [PATCH 04/62] Fix printing of extended errors. --- src/librustc/diagnostics.rs | 61 +++++++++++++++++++++---------------- src/librustc_driver/lib.rs | 3 +- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 0a29ed90ad461..34f8f34b55505 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -10,45 +10,52 @@ #![allow(non_snake_case)] +// Error messages for EXXXX errors. +// Each message should start and end with a new line, and be wrapped to 80 characters. +// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. register_long_diagnostics! { - E0001: r##" - This error suggests that the expression arm corresponding to the noted pattern - will never be reached as for all possible values of the expression being matched, - one of the preceding patterns will match. - This means that perhaps some of the preceding patterns are too general, this - one is too specific or the ordering is incorrect. +E0001: r##" +This error suggests that the expression arm corresponding to the noted pattern +will never be reached as for all possible values of the expression being +matched, one of the preceding patterns will match. + +This means that perhaps some of the preceding patterns are too general, this one +is too specific or the ordering is incorrect. "##, - E0003: r##" - Not-a-Number (NaN) values can not be compared for equality and hence can never match - the input to a match expression. To match against NaN values, you should instead use - the `is_nan` method in a guard, as in: x if x.is_nan() => ... +E0003: r##" +Not-a-Number (NaN) values can not be compared for equality and hence can never +match the input to a match expression. To match against NaN values, you should +instead use the `is_nan` method in a guard, as in: x if x.is_nan() => ... "##, - E0004: r##" - This error indicates that the compiler can not guarantee a matching pattern for one - or more possible inputs to a match expression. Guaranteed matches are required in order - to assign values to match expressions, or alternatively, determine the flow of execution. +E0004: r##" +This error indicates that the compiler can not guarantee a matching pattern for +one or more possible inputs to a match expression. Guaranteed matches are +required in order to assign values to match expressions, or alternatively, +determine the flow of execution. - If you encounter this error you must alter your patterns so that every possible value of - the input type is matched. For types with a small number of variants (like enums) you - should probably cover all cases explicitly. Alternatively, the underscore `_` wildcard - pattern can be added after all other patterns to match "anything else". +If you encounter this error you must alter your patterns so that every possible +value of the input type is matched. For types with a small number of variants +(like enums) you should probably cover all cases explicitly. Alternatively, the +underscore `_` wildcard pattern can be added after all other patterns to match +"anything else". "##, - // FIXME: Remove duplication here? - E0005: r##" - Patterns used to bind names must be irrefutable, that is, they must guarantee that a - name will be extracted in all cases. If you encounter this error you probably need - to use a `match` or `if let` to deal with the possibility of failure. +// FIXME: Remove duplication here? +E0005: r##" +Patterns used to bind names must be irrefutable, that is, they must guarantee that a +name will be extracted in all cases. If you encounter this error you probably need +to use a `match` or `if let` to deal with the possibility of failure. "##, - E0006: r##" - Patterns used to bind names must be irrefutable, that is, they must guarantee that a - name will be extracted in all cases. If you encounter this error you probably need - to use a `match` or `if let` to deal with the possibility of failure. +E0006: r##" +Patterns used to bind names must be irrefutable, that is, they must guarantee that a +name will be extracted in all cases. If you encounter this error you probably need +to use a `match` or `if let` to deal with the possibility of failure. "## + } register_diagnostics! { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index b32c6829a221b..89c19cfb0b02a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -277,7 +277,8 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { Some(ref code) => { match descriptions.find_description(&code[..]) { Some(ref description) => { - println!("{}", description); + // Slice off the leading newline and print. + print!("{}", &description[1..]); } None => { early_error(&format!("no extended information for {}", code)); From 88427605bbd3271d52d064f339e344da2892b9cb Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 12 Mar 2015 00:13:37 +0100 Subject: [PATCH 05/62] Make `AdditiveIterator` and `MultiplicativeIterator` extensible Previously it could not be implemented for types outside `libcore/iter.rs` due to coherence issues. --- src/libcore/iter.rs | 130 +++++++++++++++++++++++++++++++------------- 1 file changed, 93 insertions(+), 37 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 939d9b4ab0ec4..52bad579f47d1 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -1225,7 +1225,10 @@ impl RandomAccessIterator for Rev /// A trait for iterators over elements which can be added together #[unstable(feature = "core", reason = "needs to be re-evaluated as part of numerics reform")] -pub trait AdditiveIterator { +pub trait AdditiveIterator { + /// The result of summing over the iterator. + type SumResult; + /// Iterates over the entire iterator, summing up all the elements /// /// # Examples @@ -1238,37 +1241,65 @@ pub trait AdditiveIterator { /// let mut it = a.iter().cloned(); /// assert!(it.sum() == 15); /// ``` - fn sum(self) -> A; + fn sum(self) -> Self::SumResult; +} + +/// The sum operation of an iterator's item type. Implementing this allows +/// calling `.sum()` on the iterator. +#[unstable(feature = "core", reason = "trait is experimental")] +pub trait AdditiveIteratorItem { + /// The type of the intermediate sums. + type SumResult; + /// The start value of the sum, usually something like `0`. + fn start() -> Self::SumResult; + /// Adds another element of the iterator to the intermediate sum. + fn combine(self, other: Self::SumResult) -> Self::SumResult; +} + +#[unstable(feature = "core", reason = "trait is experimental")] +impl AdditiveIterator for I where + ::Item: AdditiveIteratorItem +{ + type SumResult = <::Item as AdditiveIteratorItem>::SumResult; + fn sum(self) -> ::SumResult { + let mut sum = <::Item as AdditiveIteratorItem>::start(); + for x in self { + sum = x.combine(sum); + } + sum + } } macro_rules! impl_additive { - ($A:ty, $init:expr) => { + ($T:ty, $init:expr) => { #[unstable(feature = "core", reason = "trait is experimental")] - impl> AdditiveIterator<$A> for T { - #[inline] - fn sum(self) -> $A { - self.fold($init, |acc, x| acc + x) - } + impl AdditiveIteratorItem for $T { + type SumResult = $T; + fn start() -> $T { $init } + fn combine(self, other: $T) -> $T { self + other } } }; } -impl_additive! { i8, 0 } -impl_additive! { i16, 0 } -impl_additive! { i32, 0 } -impl_additive! { i64, 0 } -impl_additive! { isize, 0 } -impl_additive! { u8, 0 } -impl_additive! { u16, 0 } -impl_additive! { u32, 0 } -impl_additive! { u64, 0 } +impl_additive! { i8, 0 } +impl_additive! { i16, 0 } +impl_additive! { i32, 0 } +impl_additive! { i64, 0 } +impl_additive! { isize, 0 } +impl_additive! { u8, 0 } +impl_additive! { u16, 0 } +impl_additive! { u32, 0 } +impl_additive! { u64, 0 } impl_additive! { usize, 0 } -impl_additive! { f32, 0.0 } -impl_additive! { f64, 0.0 } +impl_additive! { f32, 0.0 } +impl_additive! { f64, 0.0 } /// A trait for iterators over elements which can be multiplied together. #[unstable(feature = "core", reason = "needs to be re-evaluated as part of numerics reform")] -pub trait MultiplicativeIterator { +pub trait MultiplicativeIterator { + /// The result of multiplying the elements of the iterator. + type ProductResult; + /// Iterates over the entire iterator, multiplying all the elements /// /// # Examples @@ -1284,29 +1315,54 @@ pub trait MultiplicativeIterator { /// assert!(factorial(1) == 1); /// assert!(factorial(5) == 120); /// ``` - fn product(self) -> A; + fn product(self) -> Self::ProductResult; +} + +/// The product operation of an iterator's item type. Implementing this allows +/// calling `.product()` on the iterator. +#[unstable(feature = "core", reason = "trait is experimental")] +pub trait MultiplicativeIteratorItem { + /// The type of the intermediate products. + type ProductResult; + /// The start value of the product, usually something like `1`. + fn start() -> Self::ProductResult; + /// Multiplies another element of the iterator to the intermediate product. + fn combine(self, other: Self::ProductResult) -> Self::ProductResult; } -macro_rules! impl_multiplicative { - ($A:ty, $init:expr) => { +#[unstable(feature = "core", reason = "trait is experimental")] +impl MultiplicativeIterator for I where + ::Item: MultiplicativeIteratorItem +{ + type ProductResult = <::Item as MultiplicativeIteratorItem>::ProductResult; + fn product(self) -> ::ProductResult { + let mut product = <::Item as MultiplicativeIteratorItem>::start(); + for x in self { + product = x.combine(product); + } + product + } +} + +macro_rules! impl_multiplicative { + ($T:ty, $init:expr) => { #[unstable(feature = "core", reason = "trait is experimental")] - impl> MultiplicativeIterator<$A> for T { - #[inline] - fn product(self) -> $A { - self.fold($init, |acc, x| acc * x) - } + impl MultiplicativeIteratorItem for $T { + type ProductResult = $T; + fn start() -> $T { $init } + fn combine(self, other: $T) -> $T { self * other } } }; } -impl_multiplicative! { i8, 1 } -impl_multiplicative! { i16, 1 } -impl_multiplicative! { i32, 1 } -impl_multiplicative! { i64, 1 } -impl_multiplicative! { isize, 1 } -impl_multiplicative! { u8, 1 } -impl_multiplicative! { u16, 1 } -impl_multiplicative! { u32, 1 } -impl_multiplicative! { u64, 1 } +impl_multiplicative! { i8, 1 } +impl_multiplicative! { i16, 1 } +impl_multiplicative! { i32, 1 } +impl_multiplicative! { i64, 1 } +impl_multiplicative! { isize, 1 } +impl_multiplicative! { u8, 1 } +impl_multiplicative! { u16, 1 } +impl_multiplicative! { u32, 1 } +impl_multiplicative! { u64, 1 } impl_multiplicative! { usize, 1 } impl_multiplicative! { f32, 1.0 } impl_multiplicative! { f64, 1.0 } From ab3215406d0cd76ea71a554e0f4bdd16331cca7f Mon Sep 17 00:00:00 2001 From: Will Hipschman Date: Sat, 4 Apr 2015 13:13:57 -0700 Subject: [PATCH 06/62] Provide context for macro expansions which result in unparsed tokens. Issue #22425 --- src/libsyntax/ext/tt/macro_rules.rs | 17 +++++++++++++++++ src/test/compile-fail/macro-incomplete-parse.rs | 6 +++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 250ba0442babe..009075540fa1e 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -29,6 +29,11 @@ use std::rc::Rc; struct ParserAnyMacro<'a> { parser: RefCell>, + + /// Span of the expansion site of the macro this parser is for + site_span: Span, + /// The ident of the macro we're parsing + macro_ident: ast::Ident } impl<'a> ParserAnyMacro<'a> { @@ -50,6 +55,12 @@ impl<'a> ParserAnyMacro<'a> { token_str); let span = parser.span; parser.span_err(span, &msg[..]); + + let name = token::get_ident(self.macro_ident); + let msg = format!("caused by the macro expansion here; the usage \ + of `{}` is likely invalid in this context", + name); + parser.span_note(self.site_span, &msg[..]); } } } @@ -169,6 +180,12 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, // Weird, but useful for X-macros. return box ParserAnyMacro { parser: RefCell::new(p), + + // Pass along the original expansion site and the name of the macro + // so we can print a useful error message if the parse of the expanded + // macro leaves unparsed tokens. + site_span: sp, + macro_ident: name } } Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo { diff --git a/src/test/compile-fail/macro-incomplete-parse.rs b/src/test/compile-fail/macro-incomplete-parse.rs index 53b29ccb0c0c7..b3ce84c7e6f1a 100644 --- a/src/test/compile-fail/macro-incomplete-parse.rs +++ b/src/test/compile-fail/macro-incomplete-parse.rs @@ -24,12 +24,12 @@ macro_rules! ignored_pat { () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,` } -ignored_item!(); +ignored_item!(); //~ NOTE caused by the macro expansion here fn main() { - ignored_expr!(); + ignored_expr!(); //~ NOTE caused by the macro expansion here match 1 { - ignored_pat!() => (), + ignored_pat!() => (), //~ NOTE caused by the macro expansion here _ => (), } } From 63b36ea7c211406a76c34cba5ac9b7218e003757 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 7 Apr 2015 17:59:10 +1200 Subject: [PATCH 07/62] Work with assoc types in a super trait. And fix a bug with type param visibility though the Self rib. --- src/librustc_resolve/lib.rs | 12 +- src/librustc_typeck/astconv.rs | 114 ++++++++++-------- src/librustc_typeck/collect.rs | 2 +- src/test/compile-fail/self-impl.rs | 8 ++ ...r-wrong-number-number-type-parameters-1.rs | 2 +- ...r-wrong-number-number-type-parameters-3.rs | 2 +- ...gar-wrong-number-number-type-parameters.rs | 2 +- .../unboxed-closure-sugar-wrong-trait.rs | 2 +- src/test/run-pass/self-impl.rs | 21 +++- 9 files changed, 102 insertions(+), 63 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 002e5cc5e826d..f90c7640f8ce7 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1815,12 +1815,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ItemTrait(_, ref generics, ref bounds, ref trait_items) => { self.check_if_primitive_type_name(name, item.span); - self.with_self_rib(DefSelfTy(Some(local_def(item.id)), None), |this| { - // Create a new rib for the trait-wide type parameters. - this.with_type_parameter_rib(HasTypeParameters(generics, - TypeSpace, - NormalRibKind), - |this| { + // Create a new rib for the trait-wide type parameters. + self.with_type_parameter_rib(HasTypeParameters(generics, + TypeSpace, + ItemRibKind), + |this| { + this.with_self_rib(DefSelfTy(Some(local_def(item.id)), None), |this| { this.visit_generics(generics); visit::walk_ty_param_bounds_helper(this, bounds); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1e7e27762f67c..6617781ce2b0a 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -871,24 +871,11 @@ fn ast_type_binding_to_poly_projection_predicate<'tcx>( } } - if candidates.len() > 1 { - span_err!(tcx.sess, binding.span, E0217, - "ambiguous associated type: `{}` defined in multiple supertraits `{}`", - token::get_name(binding.item_name), - candidates.user_string(tcx)); - return Err(ErrorReported); - } - - let candidate = match candidates.pop() { - Some(c) => c, - None => { - span_err!(tcx.sess, binding.span, E0218, - "no associated type `{}` defined in `{}`", - token::get_name(binding.item_name), - trait_ref.user_string(tcx)); - return Err(ErrorReported); - } - }; + let candidate = try!(one_bound_for_assoc_type(tcx, + candidates, + &trait_ref.user_string(tcx), + &token::get_name(binding.item_name), + binding.span)); Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------------+ projection_ty: ty::ProjectionTy { // | @@ -1042,19 +1029,18 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt, } // Search for a bound on a type parameter which includes the associated item -// given by assoc_name. We assume that ty_path_def is the def for such a type -// parameter (which might be `Self`). This function will fail if there are no -// suitable bounds or there is any ambiguity. +// given by assoc_name. ty_param_node_id is the node id for the type parameter +// (which might be `Self`, but only if it is the `Self` of a trait, not an +// impl). This function will fail if there are no suitable bounds or there is +// any ambiguity. fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, - ty_path_def: def::Def, + ty_param_node_id: ast::NodeId, assoc_name: ast::Name, span: Span) -> Result, ErrorReported> { let tcx = this.tcx(); - let ty_param_node_id = ty_path_def.local_node_id(); - let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) { Ok(v) => v, Err(ErrorReported) => { @@ -1069,35 +1055,52 @@ fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, // Check that there is exactly one way to find an associated type with the // correct name. - let mut suitable_bounds: Vec<_> = + let suitable_bounds: Vec<_> = traits::transitive_bounds(tcx, &bounds) .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name)) .collect(); - let ty_param_name = tcx.ty_param_defs.borrow().get(&ty_param_node_id).unwrap().name; - if suitable_bounds.len() == 0 { + let ty_param_name = tcx.type_parameter_def(ty_param_node_id).name; + one_bound_for_assoc_type(tcx, + suitable_bounds, + &token::get_name(ty_param_name), + &token::get_name(assoc_name), + span) +} + + +// Checks that bounds contains exactly one element and reports appropriate +// errors otherwise. +fn one_bound_for_assoc_type<'tcx>(tcx: &ty::ctxt<'tcx>, + bounds: Vec>, + ty_param_name: &str, + assoc_name: &str, + span: Span) + -> Result, ErrorReported> +{ + if bounds.len() == 0 { span_err!(tcx.sess, span, E0220, - "associated type `{}` not found for type parameter `{}`", - token::get_name(assoc_name), - token::get_name(ty_param_name)); + "associated type `{}` not found for `{}`", + assoc_name, + ty_param_name); return Err(ErrorReported); } - if suitable_bounds.len() > 1 { + if bounds.len() > 1 { span_err!(tcx.sess, span, E0221, - "ambiguous associated type `{}` in bounds of `{}`", - token::get_name(assoc_name), - token::get_name(ty_param_name)); + "ambiguous associated type `{}` in bounds of `{}`", + assoc_name, + ty_param_name); - for suitable_bound in &suitable_bounds { + for bound in &bounds { span_note!(tcx.sess, span, "associated type `{}` could derive from `{}`", - token::get_name(ty_param_name), - suitable_bound.user_string(tcx)); + ty_param_name, + bound.user_string(tcx)); } } - Ok(suitable_bounds.pop().unwrap().clone()) + Ok(bounds[0].clone()) } // Create a type from a a path to an associated type. @@ -1122,12 +1125,16 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, // Find the type of the associated item, and the trait where the associated // item is declared. - let (ty, trait_did) = match (&ty.sty, ty_path_def) { + let bound = match (&ty.sty, ty_path_def) { (_, def::DefSelfTy(Some(trait_did), Some((impl_id, _)))) => { // `Self` in an impl of a trait - we have a concrete self type and a // trait reference. match tcx.map.expect_item(impl_id).node { ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) => { + if this.ensure_super_predicates(span, trait_did).is_err() { + return (tcx.types.err, ty_path_def); + } + let trait_segment = &trait_ref.path.segments.last().unwrap(); let trait_ref = ast_path_to_mono_trait_ref(this, &ExplicitRscope, @@ -1137,8 +1144,20 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, Some(ty), trait_segment); - let ty = this.projected_ty(span, trait_ref, assoc_name); - (ty, trait_did) + let candidates: Vec = + traits::supertraits(tcx, ty::Binder(trait_ref.clone())) + .filter(|r| this.trait_defines_associated_type_named(r.def_id(), + assoc_name)) + .collect(); + + match one_bound_for_assoc_type(tcx, + candidates, + "Self", + &token::get_name(assoc_name), + span) { + Ok(bound) => bound, + Err(ErrorReported) => return (tcx.types.err, ty_path_def), + } } _ => unreachable!() } @@ -1147,17 +1166,13 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, (&ty::ty_param(_), def::DefSelfTy(Some(_), None)) => { // A type parameter or Self, we need to find the associated item from // a bound. - let bound = match find_bound_for_assoc_item(this, ty_path_def, assoc_name, span) { + let ty_param_node_id = ty_path_def.local_node_id(); + match find_bound_for_assoc_item(this, ty_param_node_id, assoc_name, span) { Ok(bound) => bound, Err(ErrorReported) => return (tcx.types.err, ty_path_def), - }; - let trait_did = bound.0.def_id; - let ty = this.projected_ty_from_poly_trait_ref(span, bound, assoc_name); - - (ty, trait_did) + } } _ => { - println!("{:?} {:?}", ty.sty, ty_path_def); report_ambiguous_associated_type(tcx, span, &ty.user_string(tcx), @@ -1167,6 +1182,9 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, } }; + let trait_did = bound.0.def_id; + let ty = this.projected_ty_from_poly_trait_ref(span, bound, assoc_name); + let item_did = if trait_did.krate == ast::LOCAL_CRATE { // `ty::trait_items` used below requires information generated // by type collection, which may be in progress at this point. diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f38ebf111fd3f..95b943b254785 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1815,7 +1815,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, ty::ty_param(p) => if p.idx > cur_idx { span_err!(tcx.sess, path.span, E0128, "type parameters with a default cannot use \ - forward declared identifiers"); + forward declared identifiers"); }, _ => {} } diff --git a/src/test/compile-fail/self-impl.rs b/src/test/compile-fail/self-impl.rs index ec913aa844dbd..d058c6a5a3b93 100644 --- a/src/test/compile-fail/self-impl.rs +++ b/src/test/compile-fail/self-impl.rs @@ -16,10 +16,18 @@ trait Foo { type Baz; } +trait SuperFoo { + type SuperBaz; +} + impl Foo for Bar { type Baz = bool; } +impl SuperFoo for Bar { + type SuperBaz = bool; +} + impl Bar { fn f() { let _: ::Baz = true; diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs index c9837da58e75a..bb7e02d0d8b9b 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs @@ -12,7 +12,7 @@ trait One { fn foo(&self) -> A; } -fn foo(_: &One()) //~ ERROR no associated type `Output` defined in `One<()>` +fn foo(_: &One()) //~ ERROR associated type `Output` not found for `One<()>` {} fn main() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs index 9f0682df3fe44..20fdd52b82a3e 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs @@ -14,7 +14,7 @@ trait Three { fn dummy(&self) -> (A,B,C); } fn foo(_: &Three()) //~^ ERROR wrong number of type arguments -//~| ERROR no associated type `Output` +//~| ERROR associated type `Output` not found {} fn main() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs index 40635cf3ddda3..027fa6b0fe3b0 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs @@ -14,7 +14,7 @@ trait Zero { fn dummy(&self); } fn foo(_: Zero()) //~^ ERROR wrong number of type arguments - //~| ERROR no associated type `Output` defined in `Zero` + //~| ERROR associated type `Output` not found for `Zero` {} fn main() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs index e6e18d996b9e2..04bbfc445edea 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs @@ -14,6 +14,6 @@ trait Trait {} fn f isize>(x: F) {} //~^ ERROR wrong number of type arguments: expected 0, found 1 -//~| ERROR no associated type `Output` +//~| ERROR associated type `Output` not found fn main() {} diff --git a/src/test/run-pass/self-impl.rs b/src/test/run-pass/self-impl.rs index 746ddc9892abe..688b66a0a8774 100644 --- a/src/test/run-pass/self-impl.rs +++ b/src/test/run-pass/self-impl.rs @@ -40,19 +40,31 @@ pub struct Baz { pub f: X, } -trait Bar { +trait SuperBar { + type SuperQux; +} + +trait Bar: SuperBar { type Qux; - fn bar(x: Self, y: &Self, z: Box) -> Self; + fn bar(x: Self, y: &Self, z: Box, _: Self::SuperQux) -> Self; fn dummy(&self, x: X) { } } +impl SuperBar for Box> { + type SuperQux = bool; +} + impl Bar for Box> { type Qux = i32; - fn bar(_x: Self, _y: &Self, _z: Box) -> Self { + fn bar(_x: Self, _y: &Self, _z: Box, _: Self::SuperQux) -> Self { let _: Self::Qux = 42; let _: >::Qux = 42; + + let _: Self::SuperQux = true; + let _: ::SuperQux = true; + box Baz { f: 42 } } } @@ -61,5 +73,6 @@ fn main() { let _: Foo = Foo::foo(Foo, &Foo, box Foo); let _: Box> = Bar::bar(box Baz { f: 42 }, &box Baz { f: 42 }, - box box Baz { f: 42 }); + box box Baz { f: 42 }, + true); } From da7529afa66c68d33944e68298e78f6203f92699 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Tue, 7 Apr 2015 21:05:22 +0900 Subject: [PATCH 08/62] Split check_cast to a separate file --- src/librustc_typeck/check/cast.rs | 179 ++++++++++++++++++++++++++++++ src/librustc_typeck/check/mod.rs | 157 +------------------------- 2 files changed, 184 insertions(+), 152 deletions(-) create mode 100644 src/librustc_typeck/check/cast.rs diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs new file mode 100644 index 0000000000000..b35e3c800fcb0 --- /dev/null +++ b/src/librustc_typeck/check/cast.rs @@ -0,0 +1,179 @@ +// 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. + +//! Code for type-checking cast expressions. + +use super::coercion; +use super::demand; +use super::FnCtxt; +use super::structurally_resolved_type; + +use lint; +use middle::infer; +use middle::ty; +use middle::ty::Ty; +use syntax::ast; +use syntax::codemap::Span; + +/// Reifies a cast check to be checked once we have full type information for +/// a function context. +pub struct CastCheck<'tcx> { + expr: ast::Expr, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, + span: Span, +} + +impl<'tcx> CastCheck<'tcx> { + pub fn new(expr: ast::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span) + -> CastCheck<'tcx> { + CastCheck { + expr: expr, + expr_ty: expr_ty, + cast_ty: cast_ty, + span: span, + } + } +} + +pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { + fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + span: Span, + t_1: Ty<'tcx>, + t_e: Ty<'tcx>) { + fcx.type_error_message(span, |actual| { + format!("illegal cast; cast through an \ + integer first: `{}` as `{}`", + actual, + fcx.infcx().ty_to_string(t_1)) + }, t_e, None); + } + + let span = cast.span; + let e = &cast.expr; + let t_e = structurally_resolved_type(fcx, span, cast.expr_ty); + let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty); + + // Check for trivial casts. + if !ty::type_has_ty_infer(t_1) { + if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) { + if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) { + fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS, + e.id, + span, + format!("trivial numeric cast: `{}` as `{}`. Cast can be \ + replaced by coercion, this might require type \ + ascription or a temporary variable", + fcx.infcx().ty_to_string(t_e), + fcx.infcx().ty_to_string(t_1))); + } else { + fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS, + e.id, + span, + format!("trivial cast: `{}` as `{}`. Cast can be \ + replaced by coercion, this might require type \ + ascription or a temporary variable", + fcx.infcx().ty_to_string(t_e), + fcx.infcx().ty_to_string(t_1))); + } + return; + } + } + + let t_e_is_bare_fn_item = ty::type_is_bare_fn_item(t_e); + let t_e_is_scalar = ty::type_is_scalar(t_e); + let t_e_is_integral = ty::type_is_integral(t_e); + let t_e_is_float = ty::type_is_floating_point(t_e); + let t_e_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_e); + + let t_1_is_scalar = ty::type_is_scalar(t_1); + let t_1_is_char = ty::type_is_char(t_1); + let t_1_is_bare_fn = ty::type_is_bare_fn(t_1); + let t_1_is_float = ty::type_is_floating_point(t_1); + + // casts to scalars other than `char` and `bare fn` are trivial + let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn; + + if t_e_is_bare_fn_item && t_1_is_bare_fn { + demand::coerce(fcx, e.span, t_1, &e); + } else if t_1_is_char { + let t_e = fcx.infcx().shallow_resolve(t_e); + if t_e.sty != ty::ty_uint(ast::TyU8) { + fcx.type_error_message(span, |actual| { + format!("only `u8` can be cast as `char`, not `{}`", actual) + }, t_e, None); + } + } else if t_1.sty == ty::ty_bool { + span_err!(fcx.tcx().sess, span, E0054, + "cannot cast as `bool`, compare with zero instead"); + } else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) && !( + t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) { + // Casts to float must go through an integer or boolean + cast_through_integer_err(fcx, span, t_1, t_e) + } else if t_e_is_c_enum && t_1_is_trivial { + if ty::type_is_unsafe_ptr(t_1) { + // ... and likewise with C enum -> *T + cast_through_integer_err(fcx, span, t_1, t_e) + } + // casts from C-like enums are allowed + } else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) { + fn types_compatible<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, + t1: Ty<'tcx>, t2: Ty<'tcx>) -> bool { + match t1.sty { + ty::ty_vec(_, Some(_)) => {} + _ => return false + } + if ty::type_needs_infer(t2) { + // This prevents this special case from going off when casting + // to a type that isn't fully specified; e.g. `as *_`. (Issue + // #14893.) + return false + } + + let el = ty::sequence_element_type(fcx.tcx(), t1); + infer::mk_eqty(fcx.infcx(), + false, + infer::Misc(sp), + el, + t2).is_ok() + } + + // Due to the limitations of LLVM global constants, + // region pointers end up pointing at copies of + // vector elements instead of the original values. + // To allow unsafe pointers to work correctly, we + // need to special-case obtaining an unsafe pointer + // from a region pointer to a vector. + + /* this cast is only allowed from &[T, ..n] to *T or + &T to *T. */ + match (&t_e.sty, &t_1.sty) { + (&ty::ty_rptr(_, ty::mt { ty: mt1, mutbl: ast::MutImmutable }), + &ty::ty_ptr(ty::mt { ty: mt2, mutbl: ast::MutImmutable })) + if types_compatible(fcx, e.span, mt1, mt2) => { + /* this case is allowed */ + } + _ => { + demand::coerce(fcx, e.span, t_1, &e); + } + } + } else if !(t_e_is_scalar && t_1_is_trivial) { + /* + If more type combinations should be supported than are + supported here, then file an enhancement issue and + record the issue number in this comment. + */ + fcx.type_error_message(span, |actual| { + format!("non-scalar cast: `{}` as `{}`", + actual, + fcx.infcx().ty_to_string(t_1)) + }, t_e, None); + } +} diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 156fbfede9c98..f9bf3eaf3ddf6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -139,6 +139,7 @@ pub mod demand; pub mod method; mod upvar; pub mod wf; +mod cast; mod closure; mod callee; mod compare_method; @@ -185,7 +186,7 @@ pub struct Inherited<'a, 'tcx: 'a> { // back and process them. deferred_call_resolutions: RefCell>>>, - deferred_cast_checks: RefCell>>, + deferred_cast_checks: RefCell>>, } trait DeferredCallResolution<'tcx> { @@ -194,15 +195,6 @@ trait DeferredCallResolution<'tcx> { type DeferredCallResolutionHandler<'tcx> = Box+'tcx>; -/// Reifies a cast check to be checked once we have full type information for -/// a function context. -struct CastCheck<'tcx> { - expr: ast::Expr, - expr_ty: Ty<'tcx>, - cast_ty: Ty<'tcx>, - span: Span, -} - /// When type-checking an expression, we propagate downward /// whatever type hint we are able in the form of an `Expectation`. #[derive(Copy, Clone)] @@ -1071,141 +1063,6 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } -fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { - fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - t_1: Ty<'tcx>, - t_e: Ty<'tcx>) { - fcx.type_error_message(span, |actual| { - format!("illegal cast; cast through an \ - integer first: `{}` as `{}`", - actual, - fcx.infcx().ty_to_string(t_1)) - }, t_e, None); - } - - let span = cast.span; - let e = &cast.expr; - let t_e = structurally_resolved_type(fcx, span, cast.expr_ty); - let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty); - - // Check for trivial casts. - if !ty::type_has_ty_infer(t_1) { - if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) { - if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) { - fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS, - e.id, - span, - format!("trivial numeric cast: `{}` as `{}`. Cast can be \ - replaced by coercion, this might require type \ - ascription or a temporary variable", - fcx.infcx().ty_to_string(t_e), - fcx.infcx().ty_to_string(t_1))); - } else { - fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS, - e.id, - span, - format!("trivial cast: `{}` as `{}`. Cast can be \ - replaced by coercion, this might require type \ - ascription or a temporary variable", - fcx.infcx().ty_to_string(t_e), - fcx.infcx().ty_to_string(t_1))); - } - return; - } - } - - let t_e_is_bare_fn_item = ty::type_is_bare_fn_item(t_e); - let t_e_is_scalar = ty::type_is_scalar(t_e); - let t_e_is_integral = ty::type_is_integral(t_e); - let t_e_is_float = ty::type_is_floating_point(t_e); - let t_e_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_e); - - let t_1_is_scalar = ty::type_is_scalar(t_1); - let t_1_is_char = ty::type_is_char(t_1); - let t_1_is_bare_fn = ty::type_is_bare_fn(t_1); - let t_1_is_float = ty::type_is_floating_point(t_1); - - // casts to scalars other than `char` and `bare fn` are trivial - let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn; - - if t_e_is_bare_fn_item && t_1_is_bare_fn { - demand::coerce(fcx, e.span, t_1, &e); - } else if t_1_is_char { - let t_e = fcx.infcx().shallow_resolve(t_e); - if t_e.sty != ty::ty_uint(ast::TyU8) { - fcx.type_error_message(span, |actual| { - format!("only `u8` can be cast as `char`, not `{}`", actual) - }, t_e, None); - } - } else if t_1.sty == ty::ty_bool { - span_err!(fcx.tcx().sess, span, E0054, - "cannot cast as `bool`, compare with zero instead"); - } else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) && !( - t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) { - // Casts to float must go through an integer or boolean - cast_through_integer_err(fcx, span, t_1, t_e) - } else if t_e_is_c_enum && t_1_is_trivial { - if ty::type_is_unsafe_ptr(t_1) { - // ... and likewise with C enum -> *T - cast_through_integer_err(fcx, span, t_1, t_e) - } - // casts from C-like enums are allowed - } else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) { - fn types_compatible<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, - t1: Ty<'tcx>, t2: Ty<'tcx>) -> bool { - match t1.sty { - ty::ty_vec(_, Some(_)) => {} - _ => return false - } - if ty::type_needs_infer(t2) { - // This prevents this special case from going off when casting - // to a type that isn't fully specified; e.g. `as *_`. (Issue - // #14893.) - return false - } - - let el = ty::sequence_element_type(fcx.tcx(), t1); - infer::mk_eqty(fcx.infcx(), - false, - infer::Misc(sp), - el, - t2).is_ok() - } - - // Due to the limitations of LLVM global constants, - // region pointers end up pointing at copies of - // vector elements instead of the original values. - // To allow unsafe pointers to work correctly, we - // need to special-case obtaining an unsafe pointer - // from a region pointer to a vector. - - /* this cast is only allowed from &[T, ..n] to *T or - &T to *T. */ - match (&t_e.sty, &t_1.sty) { - (&ty::ty_rptr(_, ty::mt { ty: mt1, mutbl: ast::MutImmutable }), - &ty::ty_ptr(ty::mt { ty: mt2, mutbl: ast::MutImmutable })) - if types_compatible(fcx, e.span, mt1, mt2) => { - /* this case is allowed */ - } - _ => { - demand::coerce(fcx, e.span, t_1, &e); - } - } - } else if !(t_e_is_scalar && t_1_is_trivial) { - /* - If more type combinations should be supported than are - supported here, then file an enhancement issue and - record the issue number in this comment. - */ - fcx.type_error_message(span, |actual| { - format!("non-scalar cast: `{}` as `{}`", - actual, - fcx.infcx().ty_to_string(t_1)) - }, t_e, None); - } -} - impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx } @@ -1925,7 +1782,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_casts(&self) { let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut(); for check in deferred_cast_checks.iter() { - check_cast(self, check); + cast::check_cast(self, check); } deferred_cast_checks.clear(); @@ -3531,12 +3388,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Defer other checks until we're done type checking. let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut(); - deferred_cast_checks.push(CastCheck { - expr: (**e).clone(), - expr_ty: t_e, - cast_ty: t_1, - span: expr.span, - }); + let cast_check = cast::CastCheck::new((**e).clone(), t_e, t_1, expr.span); + deferred_cast_checks.push(cast_check); } } ast::ExprVec(ref args) => { From f4c2228be05887aeaee741c37715f6a1f2b51a5d Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Tue, 7 Apr 2015 22:45:10 +0900 Subject: [PATCH 09/62] Check casts from float --- src/librustc_typeck/check/cast.rs | 6 ++++++ src/test/compile-fail/unsupported-cast.rs | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index b35e3c800fcb0..b7aebff9ac096 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -94,9 +94,11 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { let t_e_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_e); let t_1_is_scalar = ty::type_is_scalar(t_1); + let t_1_is_integral = ty::type_is_integral(t_1); let t_1_is_char = ty::type_is_char(t_1); let t_1_is_bare_fn = ty::type_is_bare_fn(t_1); let t_1_is_float = ty::type_is_floating_point(t_1); + let t_1_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_1); // casts to scalars other than `char` and `bare fn` are trivial let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn; @@ -113,6 +115,10 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { } else if t_1.sty == ty::ty_bool { span_err!(fcx.tcx().sess, span, E0054, "cannot cast as `bool`, compare with zero instead"); + } else if t_e_is_float && (t_1_is_scalar || t_1_is_c_enum) && !( + t_1_is_integral || t_1_is_float) { + // Casts from float must go through an integer + cast_through_integer_err(fcx, span, t_1, t_e) } else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) && !( t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) { // Casts to float must go through an integer or boolean diff --git a/src/test/compile-fail/unsupported-cast.rs b/src/test/compile-fail/unsupported-cast.rs index ca17c898ec37c..b4246f2ed87f3 100644 --- a/src/test/compile-fail/unsupported-cast.rs +++ b/src/test/compile-fail/unsupported-cast.rs @@ -8,8 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-test FIXME: #13993 -// error-pattern:unsupported cast +// error-pattern:illegal cast + +#![feature(libc)] extern crate libc; From d18b405faf09514febc4163d96e85e57e137df81 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Wed, 8 Apr 2015 00:45:57 +0900 Subject: [PATCH 10/62] Check casts from fat pointer --- src/librustc_typeck/check/cast.rs | 5 +++++ src/librustc_typeck/check/mod.rs | 10 ++++++++++ src/test/compile-fail/fat-ptr-cast.rs | 14 ++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 src/test/compile-fail/fat-ptr-cast.rs diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index b7aebff9ac096..045b88e2357cd 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -170,6 +170,11 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { demand::coerce(fcx, e.span, t_1, &e); } } + } else if fcx.type_is_fat_ptr(t_e, span) && !fcx.type_is_fat_ptr(t_1, span) { + fcx.type_error_message(span, |actual| { + format!("illegal cast; cast from fat pointer: `{}` as `{}`", + actual, fcx.infcx().ty_to_string(t_1)) + }, t_e, None); } else if !(t_e_is_scalar && t_1_is_trivial) { /* If more type combinations should be supported than are diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f9bf3eaf3ddf6..cab6f76d0271b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1559,6 +1559,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span) } + pub fn type_is_fat_ptr(&self, ty: Ty<'tcx>, span: Span) -> bool { + match ty.sty { + ty::ty_ptr(ty::mt { ty: t, .. }) | + ty::ty_rptr(_, ty::mt { ty: t, .. }) => { + !self.type_is_known_to_be_sized(t, span) + } + _ => false + } + } + pub fn register_builtin_bound(&self, ty: Ty<'tcx>, builtin_bound: ty::BuiltinBound, diff --git a/src/test/compile-fail/fat-ptr-cast.rs b/src/test/compile-fail/fat-ptr-cast.rs new file mode 100644 index 0000000000000..839ebbd279a99 --- /dev/null +++ b/src/test/compile-fail/fat-ptr-cast.rs @@ -0,0 +1,14 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let a: &[i32] = &[1, 2, 3]; + a as *const [i32] as usize; //~ ERROR cast from fat pointer +} From 039a5539986b38852bca772b8709bab533ca5be0 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Mon, 6 Apr 2015 23:49:40 -0700 Subject: [PATCH 11/62] Add more extended error messages for match exprs. --- src/librustc/diagnostics.rs | 87 ++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 34f8f34b55505..b15304d6dc50c 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -24,14 +24,24 @@ This means that perhaps some of the preceding patterns are too general, this one is too specific or the ordering is incorrect. "##, +E0002: r##" +This error indicates that an empty match expression is illegal because the type +it is matching on is non-empty (there exist values of this type). In safe code +it is impossible to create an instance of an empty type, so empty match +expressions are almost never desired. This error is typically fixed by adding +one or more cases to the match expression. + +An example of an empty type is `enum Empty { }`. +"##, + E0003: r##" -Not-a-Number (NaN) values can not be compared for equality and hence can never +Not-a-Number (NaN) values cannot be compared for equality and hence can never match the input to a match expression. To match against NaN values, you should instead use the `is_nan` method in a guard, as in: x if x.is_nan() => ... "##, E0004: r##" -This error indicates that the compiler can not guarantee a matching pattern for +This error indicates that the compiler cannot guarantee a matching pattern for one or more possible inputs to a match expression. Guaranteed matches are required in order to assign values to match expressions, or alternatively, determine the flow of execution. @@ -54,14 +64,80 @@ E0006: r##" Patterns used to bind names must be irrefutable, that is, they must guarantee that a name will be extracted in all cases. If you encounter this error you probably need to use a `match` or `if let` to deal with the possibility of failure. +"##, + +E0007: r##" +This error indicates that the bindings in a match arm would require a value to +be moved into more than one location, thus violating unique ownership. Code like +the following is invalid as it requires the entire Option to be moved +into a variable called `op_string` while simultaneously requiring the inner +String to be moved into a variable called `s`. + +let x = Some("s".to_string()); +match x { + op_string @ Some(s) => ... + None => ... +} + +See also Error 303. +"##, + +E0008: r##" +Names bound in match arms retain their type in pattern guards. As such, if a +name is bound by move in a pattern, it should also be moved to wherever it is +referenced in the pattern guard code. Doing so however would prevent the name +from being available in the body of the match arm. Consider the following: + +match Some("hi".to_string()) { + Some(s) if s.len() == 0 => // use s. + ... +} + +The variable `s` has type String, and its use in the guard is as a variable of +type String. The guard code effectively executes in a separate scope to the body +of the arm, so the value would be moved into this anonymous scope and therefore +become unavailable in the body of the arm. Although this example seems +innocuous, the problem is most clear when considering functions that take their +argument by value. + +match Some("hi".to_string()) { + Some(s) if { drop(s); false } => (), + Some(s) => // use s. + ... +} + +The value would be dropped in the guard then become unavailable not only in the +body of that arm but also in all subsequent arms! The solution is to bind by +reference when using guards or refactor the entire expression, perhaps by +putting the condition inside the body of the arm. +"##, + +E0303: r##" +In certain cases it is possible for sub-bindings to violate memory safety. +Updates to the borrow checker in a future version of Rust may remove this +restriction, but for now patterns must be rewritten without sub-bindings. + +// Code like this... +match Some(5) { + ref op_num @ Some(num) => ... + None => ... +} + +// ... should be updated to code like this. +match Some(5) { + Some(num) => { + let op_num = &Some(num); + ... + } + None => ... +} + +See also https://github.com/rust-lang/rust/issues/14587 "## } register_diagnostics! { - E0002, - E0007, - E0008, E0009, E0010, E0011, @@ -124,7 +200,6 @@ register_diagnostics! { E0300, // unexpanded macro E0301, // cannot mutable borrow in a pattern guard E0302, // cannot assign in a pattern guard - E0303, // pattern bindings are not allowed after an `@` E0304, // expected signed integer constant E0305, // expected constant E0306, // expected positive integer for repeat count From 4cf59304c1e112c3b0fbedc6034b2a469fb9fce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Niemier?= Date: Tue, 7 Apr 2015 20:35:54 +0200 Subject: [PATCH 12/62] Remove incorrect example from docs --- src/libstd/sync/mpsc/mod.rs | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index c80182ec07d32..a955f88164c4f 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -113,32 +113,6 @@ //! rx.recv().unwrap(); //! ``` //! -//! Reading from a channel with a timeout requires to use a Timer together -//! with the channel. You can use the `select!` macro to select either and -//! handle the timeout case. This first example will break out of the loop -//! after 10 seconds no matter what: -//! -//! ```no_run -//! # #![feature(std_misc, old_io)] -//! use std::sync::mpsc::channel; -//! use std::old_io::timer::Timer; -//! use std::time::Duration; -//! -//! let (tx, rx) = channel::(); -//! let mut timer = Timer::new().unwrap(); -//! let timeout = timer.oneshot(Duration::seconds(10)); -//! -//! loop { -//! select! { -//! val = rx.recv() => println!("Received {}", val.unwrap()), -//! _ = timeout.recv() => { -//! println!("timed out, total time was more than 10 seconds"); -//! break; -//! } -//! } -//! } -//! ``` -//! //! This second example is more costly since it allocates a new timer every //! time a message is received, but it allows you to timeout after the channel //! has been inactive for 5 seconds: From df95719391b2ee94c09162060052755e75f431dc Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Tue, 7 Apr 2015 12:36:39 -0700 Subject: [PATCH 13/62] Add Clone impls for extern "C" and unsafe fns We only implemented Clone on `extern "Rust" fn`s (for up to 8 parameters). This didn't cover `extern "C"` or `unsafe` (or `unsafe extern "C"`) `fn`s, but there's no reason why they shouldn't be cloneable as well. The new impls are marked unstable because the existing impl for `extern "Rust" fn`s is. Fixes #24161. --- src/libcore/clone.rs | 21 +++++++++++++++++++++ src/test/run-pass/issue-24161.rs | 19 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/test/run-pass/issue-24161.rs diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 85e5bde48598e..91747d7405ff6 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -97,6 +97,27 @@ macro_rules! extern_fn_clone { #[inline] fn clone(&self) -> extern "Rust" fn($($A),*) -> ReturnType { *self } } + + #[unstable(feature = "core", reason = "brand new")] + impl<$($A,)* ReturnType> Clone for extern "C" fn($($A),*) -> ReturnType { + /// Return a copy of a function pointer + #[inline] + fn clone(&self) -> extern "C" fn($($A),*) -> ReturnType { *self } + } + + #[unstable(feature = "core", reason = "brand new")] + impl<$($A,)* ReturnType> Clone for unsafe extern "Rust" fn($($A),*) -> ReturnType { + /// Return a copy of a function pointer + #[inline] + fn clone(&self) -> unsafe extern "Rust" fn($($A),*) -> ReturnType { *self } + } + + #[unstable(feature = "core", reason = "brand new")] + impl<$($A,)* ReturnType> Clone for unsafe extern "C" fn($($A),*) -> ReturnType { + /// Return a copy of a function pointer + #[inline] + fn clone(&self) -> unsafe extern "C" fn($($A),*) -> ReturnType { *self } + } ) } diff --git a/src/test/run-pass/issue-24161.rs b/src/test/run-pass/issue-24161.rs new file mode 100644 index 0000000000000..2445ef17ecf3b --- /dev/null +++ b/src/test/run-pass/issue-24161.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[derive(Copy,Clone)] +struct Functions { + a: fn(u32) -> u32, + b: extern "C" fn(u32) -> u32, + c: unsafe fn(u32) -> u32, + d: unsafe extern "C" fn(u32) -> u32 +} + +pub fn main() {} From 4695bf070585ec74c3c7fb396c11b4f728f6866a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Niemier?= Date: Tue, 7 Apr 2015 21:46:14 +0200 Subject: [PATCH 14/62] Remove another invalid example --- src/libstd/sync/mpsc/mod.rs | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index a955f88164c4f..e544484351600 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -112,32 +112,6 @@ //! }); //! rx.recv().unwrap(); //! ``` -//! -//! This second example is more costly since it allocates a new timer every -//! time a message is received, but it allows you to timeout after the channel -//! has been inactive for 5 seconds: -//! -//! ```no_run -//! # #![feature(std_misc, old_io)] -//! use std::sync::mpsc::channel; -//! use std::old_io::timer::Timer; -//! use std::time::Duration; -//! -//! let (tx, rx) = channel::(); -//! let mut timer = Timer::new().unwrap(); -//! -//! loop { -//! let timeout = timer.oneshot(Duration::seconds(5)); -//! -//! select! { -//! val = rx.recv() => println!("Received {}", val.unwrap()), -//! _ = timeout.recv() => { -//! println!("timed out, no message received in 5 seconds"); -//! break; -//! } -//! } -//! } -//! ``` #![stable(feature = "rust1", since = "1.0.0")] From 334422184eebb108b54d7c0a19e186ebb06e89ee Mon Sep 17 00:00:00 2001 From: Hajime Morrita Date: Tue, 7 Apr 2015 13:19:17 -0700 Subject: [PATCH 15/62] Fix a typo --- src/doc/trpl/associated-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/trpl/associated-types.md b/src/doc/trpl/associated-types.md index 7161cd33f89be..d59239016d881 100644 --- a/src/doc/trpl/associated-types.md +++ b/src/doc/trpl/associated-types.md @@ -198,5 +198,5 @@ let obj = Box::new(graph) as Box>; ``` The `N=Node` syntax allows us to provide a concrete type, `Node`, for the `N` -type parameter. Same with `E=Edge`. If we didn’t proide this constraint, we +type parameter. Same with `E=Edge`. If we didn’t provide this constraint, we couldn’t be sure which `impl` to match this trait object to. From 9a51c63a2fa4ad38f0ff90649b948d2e5b667d19 Mon Sep 17 00:00:00 2001 From: Ralph Giles Date: Tue, 7 Apr 2015 14:05:02 -0700 Subject: [PATCH 16/62] rustup: let RUSTUP_PREFIX env override default prefix. The idea here is if you don't want rust in /usr/local you can put something like this is your .profile: export RUSTUP_PREFIX=$HOME/.local/rust export PATH=$PATH:${RUSTUP_PREFIX}/bin export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:${RUSTUP_PREFIX}/lib Then when you run rustup, it will update the install in ${RUSTUP_PREFIX} without having to remember to pass an explicit --prefix argument every time. --- src/etc/rustup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etc/rustup.sh b/src/etc/rustup.sh index 918c0c66f76df..7c207385393c9 100755 --- a/src/etc/rustup.sh +++ b/src/etc/rustup.sh @@ -286,7 +286,7 @@ BOOL_OPTIONS="" VAL_OPTIONS="" flag uninstall "only uninstall from the installation prefix" -valopt prefix "" "set installation prefix" +valopt prefix "${RUSTUP_PREFIX}" "set installation prefix" valopt date "" "use the YYYY-MM-DD nightly instead of the current nightly" valopt channel "beta" "use the selected release channel [beta]" flag save "save the downloaded nightlies to ~/.rustup" From 97f24a85965c3c51a2c18be029091ae52bbd7920 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 6 Apr 2015 17:43:50 +0200 Subject: [PATCH 17/62] Make `sum` and `product` inherent methods on `Iterator` In addition to being nicer, this also allows you to use `sum` and `product` for iterators yielding custom types aside from the standard integers. Due to removing the `AdditiveIterator` and `MultiplicativeIterator` trait, this is a breaking change. [breaking-change] --- src/libcollections/slice.rs | 3 +- src/libcollections/str.rs | 3 +- src/libcollectionstest/str.rs | 1 - src/libcore/iter.rs | 201 +++++------------- src/libcore/num/mod.rs | 14 ++ src/libcoretest/iter.rs | 12 +- src/librustc/middle/check_match.rs | 4 +- src/librustc_trans/trans/_match.rs | 1 - src/librustc_typeck/astconv.rs | 15 +- src/libstd/old_path/posix.rs | 5 +- src/libstd/old_path/windows.rs | 5 +- src/libunicode/u_str.rs | 2 +- src/rustbook/book.rs | 3 +- src/test/bench/shootout-spectralnorm.rs | 2 +- src/test/run-pass/issue-15673.rs | 3 +- .../run-pass/iter-cloned-type-inference.rs | 4 +- 16 files changed, 89 insertions(+), 189 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index ff923fb19068f..8622b8cd93568 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -85,7 +85,6 @@ use core::clone::Clone; use core::cmp::Ordering::{self, Greater, Less}; use core::cmp::{self, Ord, PartialEq}; use core::iter::Iterator; -use core::iter::MultiplicativeIterator; use core::marker::Sized; use core::mem::size_of; use core::mem; @@ -1182,7 +1181,7 @@ impl Iterator for ElementSwaps { #[inline] fn size_hint(&self) -> (usize, Option) { // For a vector of size n, there are exactly n! permutations. - let n = (2..self.sdir.len() + 1).product(); + let n: usize = (2..self.sdir.len() + 1).product(); (n - self.swaps_made, Some(n - self.swaps_made)) } } diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index c22b6fb9286d1..c5de430ae8ce2 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -53,7 +53,6 @@ use self::RecompositionState::*; use self::DecompositionType::*; use core::clone::Clone; -use core::iter::AdditiveIterator; use core::iter::{Iterator, Extend}; use core::option::Option::{self, Some, None}; use core::result::Result; @@ -112,7 +111,7 @@ impl> SliceConcatExt for [S] { // this is wrong without the guarantee that `self` is non-empty // `len` calculation may overflow but push_str but will check boundaries let len = sep.len() * (self.len() - 1) - + self.iter().map(|s| s.as_ref().len()).sum(); + + self.iter().map(|s| s.as_ref().len()).sum::(); let mut result = String::with_capacity(len); let mut first = true; diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 495a961fa360e..63e4005fadeba 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -9,7 +9,6 @@ // except according to those terms. use std::cmp::Ordering::{Equal, Greater, Less}; -use std::iter::AdditiveIterator; use std::str::{Utf8Error, from_utf8}; #[test] diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 52bad579f47d1..84726df8fdbc5 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -65,7 +65,7 @@ use default::Default; use marker; use mem; use num::{Int, Zero, One}; -use ops::{self, Add, Sub, FnMut, RangeFrom}; +use ops::{self, Add, Sub, FnMut, Mul, RangeFrom}; use option::Option::{self, Some, None}; use marker::Sized; use usize; @@ -489,15 +489,14 @@ pub trait Iterator { /// /// ``` /// # #![feature(core)] - /// use std::iter::AdditiveIterator; /// /// let a = [1, 4, 2, 3, 8, 9, 6]; - /// let sum = a.iter() - /// .map(|x| *x) - /// .inspect(|&x| println!("filtering {}", x)) - /// .filter(|&x| x % 2 == 0) - /// .inspect(|&x| println!("{} made it through", x)) - /// .sum(); + /// let sum: i32 = a.iter() + /// .map(|x| *x) + /// .inspect(|&x| println!("filtering {}", x)) + /// .filter(|&x| x % 2 == 0) + /// .inspect(|&x| println!("{} made it through", x)) + /// .sum(); /// println!("{}", sum); /// ``` #[inline] @@ -1022,6 +1021,47 @@ pub trait Iterator { } } } + + /// Iterates over the entire iterator, summing up all the elements + /// + /// # Examples + /// + /// ``` + /// # #![feature(core)] + /// + /// let a = [1, 2, 3, 4, 5]; + /// let mut it = a.iter().cloned(); + /// assert!(it.sum::() == 15); + /// ``` + #[unstable(feature="core")] + fn sum::Item>(self) -> S where + S: Add + Zero, + Self: Sized, + { + self.fold(Zero::zero(), |s, e| s + e) + } + + /// Iterates over the entire iterator, multiplying all the elements + /// + /// # Examples + /// + /// ``` + /// # #![feature(core)] + /// + /// fn factorial(n: u32) -> u32 { + /// (1..).take_while(|&i| i <= n).product() + /// } + /// assert!(factorial(0) == 1); + /// assert!(factorial(1) == 1); + /// assert!(factorial(5) == 120); + /// ``` + #[unstable(feature="core")] + fn product::Item>(self) -> P where + P: Mul + One, + Self: Sized, + { + self.fold(One::one(), |p, e| p * e) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1222,151 +1262,6 @@ impl RandomAccessIterator for Rev } } -/// A trait for iterators over elements which can be added together -#[unstable(feature = "core", - reason = "needs to be re-evaluated as part of numerics reform")] -pub trait AdditiveIterator { - /// The result of summing over the iterator. - type SumResult; - - /// Iterates over the entire iterator, summing up all the elements - /// - /// # Examples - /// - /// ``` - /// # #![feature(core)] - /// use std::iter::AdditiveIterator; - /// - /// let a = [1, 2, 3, 4, 5]; - /// let mut it = a.iter().cloned(); - /// assert!(it.sum() == 15); - /// ``` - fn sum(self) -> Self::SumResult; -} - -/// The sum operation of an iterator's item type. Implementing this allows -/// calling `.sum()` on the iterator. -#[unstable(feature = "core", reason = "trait is experimental")] -pub trait AdditiveIteratorItem { - /// The type of the intermediate sums. - type SumResult; - /// The start value of the sum, usually something like `0`. - fn start() -> Self::SumResult; - /// Adds another element of the iterator to the intermediate sum. - fn combine(self, other: Self::SumResult) -> Self::SumResult; -} - -#[unstable(feature = "core", reason = "trait is experimental")] -impl AdditiveIterator for I where - ::Item: AdditiveIteratorItem -{ - type SumResult = <::Item as AdditiveIteratorItem>::SumResult; - fn sum(self) -> ::SumResult { - let mut sum = <::Item as AdditiveIteratorItem>::start(); - for x in self { - sum = x.combine(sum); - } - sum - } -} - -macro_rules! impl_additive { - ($T:ty, $init:expr) => { - #[unstable(feature = "core", reason = "trait is experimental")] - impl AdditiveIteratorItem for $T { - type SumResult = $T; - fn start() -> $T { $init } - fn combine(self, other: $T) -> $T { self + other } - } - }; -} -impl_additive! { i8, 0 } -impl_additive! { i16, 0 } -impl_additive! { i32, 0 } -impl_additive! { i64, 0 } -impl_additive! { isize, 0 } -impl_additive! { u8, 0 } -impl_additive! { u16, 0 } -impl_additive! { u32, 0 } -impl_additive! { u64, 0 } -impl_additive! { usize, 0 } -impl_additive! { f32, 0.0 } -impl_additive! { f64, 0.0 } - -/// A trait for iterators over elements which can be multiplied together. -#[unstable(feature = "core", - reason = "needs to be re-evaluated as part of numerics reform")] -pub trait MultiplicativeIterator { - /// The result of multiplying the elements of the iterator. - type ProductResult; - - /// Iterates over the entire iterator, multiplying all the elements - /// - /// # Examples - /// - /// ``` - /// # #![feature(core)] - /// use std::iter::MultiplicativeIterator; - /// - /// fn factorial(n: usize) -> usize { - /// (1..).take_while(|&i| i <= n).product() - /// } - /// assert!(factorial(0) == 1); - /// assert!(factorial(1) == 1); - /// assert!(factorial(5) == 120); - /// ``` - fn product(self) -> Self::ProductResult; -} - -/// The product operation of an iterator's item type. Implementing this allows -/// calling `.product()` on the iterator. -#[unstable(feature = "core", reason = "trait is experimental")] -pub trait MultiplicativeIteratorItem { - /// The type of the intermediate products. - type ProductResult; - /// The start value of the product, usually something like `1`. - fn start() -> Self::ProductResult; - /// Multiplies another element of the iterator to the intermediate product. - fn combine(self, other: Self::ProductResult) -> Self::ProductResult; -} - -#[unstable(feature = "core", reason = "trait is experimental")] -impl MultiplicativeIterator for I where - ::Item: MultiplicativeIteratorItem -{ - type ProductResult = <::Item as MultiplicativeIteratorItem>::ProductResult; - fn product(self) -> ::ProductResult { - let mut product = <::Item as MultiplicativeIteratorItem>::start(); - for x in self { - product = x.combine(product); - } - product - } -} - -macro_rules! impl_multiplicative { - ($T:ty, $init:expr) => { - #[unstable(feature = "core", reason = "trait is experimental")] - impl MultiplicativeIteratorItem for $T { - type ProductResult = $T; - fn start() -> $T { $init } - fn combine(self, other: $T) -> $T { self * other } - } - }; -} -impl_multiplicative! { i8, 1 } -impl_multiplicative! { i16, 1 } -impl_multiplicative! { i32, 1 } -impl_multiplicative! { i64, 1 } -impl_multiplicative! { isize, 1 } -impl_multiplicative! { u8, 1 } -impl_multiplicative! { u16, 1 } -impl_multiplicative! { u32, 1 } -impl_multiplicative! { u64, 1 } -impl_multiplicative! { usize, 1 } -impl_multiplicative! { f32, 1.0 } -impl_multiplicative! { f64, 1.0 } - /// `MinMaxResult` is an enum returned by `min_max`. See `Iterator::min_max` for /// more detail. #[derive(Clone, PartialEq, Debug)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 28e0bcf13dd09..7868e299cfcad 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -86,6 +86,20 @@ macro_rules! zero_one_impl { } zero_one_impl! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +macro_rules! zero_one_impl_float { + ($($t:ty)*) => ($( + impl Zero for $t { + #[inline] + fn zero() -> $t { 0.0 } + } + impl One for $t { + #[inline] + fn one() -> $t { 1.0 } + } + )*) +} +zero_one_impl_float! { f32 f64 } + /// A built-in signed or unsigned integer. #[stable(feature = "rust1", since = "1.0.0")] #[deprecated(since = "1.0.0", diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index af80d347f028e..bfa9c798d3579 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -329,17 +329,17 @@ fn test_iterator_len() { #[test] fn test_iterator_sum() { let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..4].iter().cloned().sum(), 6); - assert_eq!(v.iter().cloned().sum(), 55); - assert_eq!(v[..0].iter().cloned().sum(), 0); + assert_eq!(v[..4].iter().cloned().sum::(), 6); + assert_eq!(v.iter().cloned().sum::(), 55); + assert_eq!(v[..0].iter().cloned().sum::(), 0); } #[test] fn test_iterator_product() { let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..4].iter().cloned().product(), 0); - assert_eq!(v[1..5].iter().cloned().product(), 24); - assert_eq!(v[..0].iter().cloned().product(), 1); + assert_eq!(v[..4].iter().cloned().product::(), 0); + assert_eq!(v[1..5].iter().cloned().product::(), 24); + assert_eq!(v[..0].iter().cloned().product::(), 1); } #[test] diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 79f4d62b45e75..14df040fb79ed 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -26,7 +26,7 @@ use middle::ty::*; use middle::ty; use std::cmp::Ordering; use std::fmt; -use std::iter::{range_inclusive, AdditiveIterator, FromIterator, IntoIterator, repeat}; +use std::iter::{range_inclusive, FromIterator, IntoIterator, repeat}; use std::slice; use syntax::ast::{self, DUMMY_NODE_ID, NodeId, Pat}; use syntax::ast_util; @@ -76,7 +76,7 @@ impl<'a> fmt::Debug for Matrix<'a> { pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0) }).collect(); - let total_width = column_widths.iter().cloned().sum() + column_count * 3 + 1; + let total_width = column_widths.iter().cloned().sum::() + column_count * 3 + 1; let br = repeat('+').take(total_width).collect::(); try!(write!(f, "{}\n", br)); for row in pretty_printed_matrix { diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index ef599a01e7c40..15d296f71bddc 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -220,7 +220,6 @@ use util::ppaux::{Repr, vec_map_to_string}; use std; use std::cmp::Ordering; -use std::iter::AdditiveIterator; use std::rc::Rc; use syntax::ast; use syntax::ast::{DUMMY_NODE_ID, Ident, NodeId}; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 939142cff1c32..7a93873af0378 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -61,7 +61,7 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::ppaux::{self, Repr, UserString}; -use std::iter::{repeat, AdditiveIterator}; +use std::iter::repeat; use std::rc::Rc; use std::slice; use syntax::{abi, ast, ast_util}; @@ -517,12 +517,13 @@ fn find_implied_output_region(input_tys: &[Ty], input_pats: Vec) lifetimes_for_params.push((input_pat, accumulator.len())); } - let implied_output_region = if lifetimes_for_params.iter().map(|&(_, n)| n).sum() == 1 { - assert!(possible_implied_output_region.is_some()); - possible_implied_output_region - } else { - None - }; + let implied_output_region = + if lifetimes_for_params.iter().map(|&(_, n)| n).sum::() == 1 { + assert!(possible_implied_output_region.is_some()); + possible_implied_output_region + } else { + None + }; (implied_output_region, lifetimes_for_params) } diff --git a/src/libstd/old_path/posix.rs b/src/libstd/old_path/posix.rs index c517fab257f95..af63be2aa9e3f 100644 --- a/src/libstd/old_path/posix.rs +++ b/src/libstd/old_path/posix.rs @@ -15,8 +15,7 @@ use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}; use fmt; use hash; use old_io::Writer; -use iter::{AdditiveIterator, Extend}; -use iter::{Iterator, Map}; +use iter::{Extend, Iterator, Map}; use marker::Sized; use option::Option::{self, Some, None}; use result::Result::{self, Ok, Err}; @@ -351,7 +350,7 @@ impl Path { Some(vec![SEP_BYTE]) } else { let n = if is_abs { comps.len() } else { comps.len() - 1} + - comps.iter().map(|v| v.len()).sum(); + comps.iter().map(|v| v.len()).sum::(); let mut v = Vec::with_capacity(n); let mut it = comps.into_iter(); if !is_abs { diff --git a/src/libstd/old_path/windows.rs b/src/libstd/old_path/windows.rs index 0b88f368b3952..65aad38a2b43d 100644 --- a/src/libstd/old_path/windows.rs +++ b/src/libstd/old_path/windows.rs @@ -20,8 +20,7 @@ use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}; use fmt; use hash; use old_io::Writer; -use iter::{AdditiveIterator, Extend}; -use iter::{Iterator, Map, repeat}; +use iter::{Extend, Iterator, Map, repeat}; use mem; use option::Option::{self, Some, None}; use result::Result::{self, Ok, Err}; @@ -785,7 +784,7 @@ impl Path { let prefix_ = &s[..prefix_len(prefix)]; let n = prefix_.len() + if is_abs { comps.len() } else { comps.len() - 1} + - comps.iter().map(|v| v.len()).sum(); + comps.iter().map(|v| v.len()).sum::(); let mut s = String::with_capacity(n); match prefix { Some(DiskPrefix) => { diff --git a/src/libunicode/u_str.rs b/src/libunicode/u_str.rs index 3f9dd8ab635c3..2af94bf30b11d 100644 --- a/src/libunicode/u_str.rs +++ b/src/libunicode/u_str.rs @@ -20,7 +20,7 @@ use core::prelude::*; use core::char; use core::cmp; -use core::iter::{Filter, AdditiveIterator}; +use core::iter::Filter; use core::mem; use core::slice; use core::str::Split; diff --git a/src/rustbook/book.rs b/src/rustbook/book.rs index a08481f8be94e..2d630d8fe8de7 100644 --- a/src/rustbook/book.rs +++ b/src/rustbook/book.rs @@ -13,7 +13,6 @@ use std::io::prelude::*; use std::io::BufReader; use std::iter; -use std::iter::AdditiveIterator; use std::path::{Path, PathBuf}; pub struct BookItem { @@ -151,7 +150,7 @@ pub fn parse_summary(input: &mut Read, src: &Path) -> Result> '\t' => 4, _ => unreachable!() } - }).sum() / 4 + 1; + }).sum::() / 4 + 1; if level > stack.len() + 1 { errors.push(format!("section '{}' is indented too deeply; \ diff --git a/src/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index c0268e816cf3e..5fcbe77329992 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -43,7 +43,7 @@ #![allow(non_snake_case)] #![feature(unboxed_closures, core, os)] -use std::iter::{repeat, AdditiveIterator}; +use std::iter::repeat; use std::thread; use std::mem; use std::num::Float; diff --git a/src/test/run-pass/issue-15673.rs b/src/test/run-pass/issue-15673.rs index 6c76f1595dc0d..c1ecd3eba48bd 100644 --- a/src/test/run-pass/issue-15673.rs +++ b/src/test/run-pass/issue-15673.rs @@ -12,8 +12,7 @@ #![feature(core)] -use std::iter::AdditiveIterator; fn main() { let x: [u64; 3] = [1, 2, 3]; - assert_eq!(6, (0..3).map(|i| x[i]).sum()); + assert_eq!(6, (0..3).map(|i| x[i]).sum::()); } diff --git a/src/test/run-pass/iter-cloned-type-inference.rs b/src/test/run-pass/iter-cloned-type-inference.rs index 12f6a7caf6c39..d1f63564979c8 100644 --- a/src/test/run-pass/iter-cloned-type-inference.rs +++ b/src/test/run-pass/iter-cloned-type-inference.rs @@ -15,10 +15,8 @@ #![feature(core)] -use std::iter::AdditiveIterator; - fn square_sum(v: &[i64]) -> i64 { - let sum = v.iter().cloned().sum(); + let sum: i64 = v.iter().cloned().sum(); sum * sum } From dddcbcfeac13c1cf0a262e7d57e14d6588dcadc2 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Mon, 6 Apr 2015 11:07:20 -0700 Subject: [PATCH 18/62] Fix range performance regression A recent change to the implementation of range iterators meant that, even when stepping by 1, the iterators *always* involved checked arithmetic. This commit reverts to the earlier behavior (while retaining the refactoring into traits). Fixes #24095 cc #24014 --- src/libcore/iter.rs | 47 ++++++++++++++++---------------- src/test/compile-fail/range-1.rs | 1 + 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 939d9b4ab0ec4..b4fee0ffe2a95 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -60,7 +60,7 @@ use self::MinMaxResult::*; use clone::Clone; use cmp; -use cmp::Ord; +use cmp::{Ord, PartialOrd, PartialEq}; use default::Default; use marker; use mem; @@ -2431,7 +2431,7 @@ impl Iterator for Unfold where F: FnMut(&mut St) -> Option { /// two `Step` objects. #[unstable(feature = "step_trait", reason = "likely to be replaced by finer-grained traits")] -pub trait Step: Ord { +pub trait Step: PartialOrd { /// Steps `self` if possible. fn step(&self, by: &Self) -> Option; @@ -2598,7 +2598,10 @@ pub fn range_inclusive(start: A, stop: A) -> RangeInclusive #[unstable(feature = "core", reason = "likely to be replaced by range notation and adapters")] -impl Iterator for RangeInclusive { +impl Iterator for RangeInclusive where + A: PartialEq + Step + One + Clone, + for<'a> &'a A: Add<&'a A, Output = A> +{ type Item = A; #[inline] @@ -2628,9 +2631,10 @@ impl Iterator for RangeInclusive { #[unstable(feature = "core", reason = "likely to be replaced by range notation and adapters")] -impl DoubleEndedIterator for RangeInclusive - where A: Step + One + Clone, - for<'a> &'a A: Sub +impl DoubleEndedIterator for RangeInclusive where + A: PartialEq + Step + One + Clone, + for<'a> &'a A: Add<&'a A, Output = A>, + for<'a> &'a A: Sub { #[inline] fn next_back(&mut self) -> Option { @@ -2758,24 +2762,17 @@ macro_rules! range_exact_iter_impl { #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] -impl Iterator for ops::Range { +impl Iterator for ops::Range where + for<'a> &'a A: Add<&'a A, Output = A> +{ type Item = A; #[inline] fn next(&mut self) -> Option { if self.start < self.end { - match self.start.step(&A::one()) { - Some(mut n) => { - mem::swap(&mut n, &mut self.start); - Some(n) - }, - None => { - let mut n = self.end.clone(); - mem::swap(&mut n, &mut self.start); - Some(n) - - } - } + let mut n = &self.start + &A::one(); + mem::swap(&mut n, &mut self.start); + Some(n) } else { None } @@ -2797,6 +2794,7 @@ range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32); #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] impl DoubleEndedIterator for ops::Range where + for<'a> &'a A: Add<&'a A, Output = A>, for<'a> &'a A: Sub<&'a A, Output = A> { #[inline] @@ -2812,15 +2810,16 @@ impl DoubleEndedIterator for ops::Range where #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] -impl Iterator for ops::RangeFrom { +impl Iterator for ops::RangeFrom where + for<'a> &'a A: Add<&'a A, Output = A> +{ type Item = A; #[inline] fn next(&mut self) -> Option { - self.start.step(&A::one()).map(|mut n| { - mem::swap(&mut n, &mut self.start); - n - }) + let mut n = &self.start + &A::one(); + mem::swap(&mut n, &mut self.start); + Some(n) } } diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index 3ae61722bcff3..826e4283ef827 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -19,6 +19,7 @@ pub fn main() { for i in false..true {} //~^ ERROR the trait //~^^ ERROR the trait + //~^^^ ERROR the trait // Unsized type. let arr: &[_] = &[1, 2, 3]; From f354c8a580acbb3170883dd271f362d4b9132ddc Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 7 Apr 2015 19:44:49 -0400 Subject: [PATCH 19/62] New TOC --- src/doc/trpl/SUMMARY.md | 73 +- src/doc/trpl/advanced-macros.md | 242 ------ src/doc/trpl/advanced.md | 8 - src/doc/trpl/arrays-vectors-and-slices.md | 102 --- src/doc/trpl/arrays.md | 0 src/doc/trpl/associated-types.md | 202 ----- src/doc/trpl/attributes.md | 0 src/doc/trpl/basic.md | 7 - src/doc/trpl/benchmark-tests.md | 152 ---- src/doc/trpl/box-syntax-and-patterns.md | 100 --- src/doc/trpl/casting-between-types.md | 0 src/doc/trpl/closures.md | 475 ------------ src/doc/trpl/comments.md | 47 -- src/doc/trpl/compound-data-types.md | 364 --------- src/doc/trpl/conclusion.md | 11 - src/doc/trpl/concurrency.md | 358 --------- src/doc/trpl/conditional-compilation.md | 0 src/doc/trpl/const.md | 0 src/doc/trpl/crates-and-modules.md | 533 ------------- src/doc/trpl/debug-and-display.md | 0 src/doc/trpl/deref-coercions.md | 0 src/doc/trpl/documentation.md | 562 -------------- src/doc/trpl/drop.md | 0 src/doc/trpl/effective-rust.md | 0 src/doc/trpl/enums.md | 0 src/doc/trpl/error-handling.md | 301 -------- src/doc/trpl/ffi.md | 530 ------------- src/doc/trpl/for-loops.md | 0 src/doc/trpl/functions.md | 193 ----- src/doc/trpl/generics.md | 177 ----- src/doc/trpl/getting-started.md | 0 src/doc/trpl/glossary.md | 39 - src/doc/trpl/hello-cargo.md | 168 ----- src/doc/trpl/hello-world.md | 164 ---- src/doc/trpl/if.md | 155 ---- src/doc/trpl/inline-assembly.md | 141 ---- src/doc/trpl/installing-rust.md | 93 --- src/doc/trpl/intermediate.md | 7 - src/doc/trpl/intrinsics.md | 25 - src/doc/trpl/iterators.md | 349 --------- src/doc/trpl/lang-items.md | 79 -- src/doc/trpl/learn-rust.md | 0 src/doc/trpl/lifetimes.md | 0 src/doc/trpl/link-args.md | 25 - src/doc/trpl/lol.txt | 1 + src/doc/trpl/looping.md | 133 ---- src/doc/trpl/macros.md | 432 ----------- src/doc/trpl/match.md | 156 ---- src/doc/trpl/method-syntax.md | 232 ------ src/doc/trpl/more-strings.md | 325 -------- src/doc/trpl/move-semantics.md | 0 src/doc/trpl/mutability.md | 0 src/doc/trpl/{unstable.md => nightly-rust.md} | 0 src/doc/trpl/no-stdlib.md | 168 ----- src/doc/trpl/operators-and-overloading.md | 0 src/doc/trpl/ownership.md | 555 -------------- src/doc/trpl/patterns.md | 200 ----- src/doc/trpl/plugins.md | 242 ------ src/doc/trpl/pointers.md | 699 ------------------ src/doc/trpl/primitive-types.md | 0 src/doc/trpl/references-and-borrowing.md | 0 src/doc/trpl/slices.md | 0 src/doc/trpl/static-and-dynamic-dispatch.md | 306 -------- src/doc/trpl/static.md | 0 src/doc/trpl/strings.md | 61 -- src/doc/trpl/structs.md | 0 src/doc/trpl/syntax-and-semantics.md | 0 src/doc/trpl/testing.md | 432 ----------- src/doc/trpl/the-stack-and-the-heap.md | 0 src/doc/trpl/tracing-macros.md | 91 --- src/doc/trpl/trait-objects.md | 0 src/doc/trpl/traits.md | 508 ------------- src/doc/trpl/tuple-structs.md | 0 src/doc/trpl/tuples.md | 0 src/doc/trpl/type-aliases.md | 0 src/doc/trpl/ufcs.md | 0 src/doc/trpl/unsafe-code.md | 0 src/doc/trpl/unsafe.md | 183 ----- src/doc/trpl/unsized-types.md | 0 src/doc/trpl/variable-bindings.md | 161 ---- src/doc/trpl/vectors.md | 0 src/doc/trpl/while-loops.md | 0 82 files changed, 48 insertions(+), 10519 deletions(-) delete mode 100644 src/doc/trpl/advanced-macros.md delete mode 100644 src/doc/trpl/advanced.md delete mode 100644 src/doc/trpl/arrays-vectors-and-slices.md create mode 100644 src/doc/trpl/arrays.md create mode 100644 src/doc/trpl/attributes.md delete mode 100644 src/doc/trpl/basic.md create mode 100644 src/doc/trpl/casting-between-types.md delete mode 100644 src/doc/trpl/compound-data-types.md delete mode 100644 src/doc/trpl/conclusion.md create mode 100644 src/doc/trpl/conditional-compilation.md create mode 100644 src/doc/trpl/const.md create mode 100644 src/doc/trpl/debug-and-display.md create mode 100644 src/doc/trpl/deref-coercions.md create mode 100644 src/doc/trpl/drop.md create mode 100644 src/doc/trpl/effective-rust.md create mode 100644 src/doc/trpl/enums.md create mode 100644 src/doc/trpl/for-loops.md create mode 100644 src/doc/trpl/getting-started.md delete mode 100644 src/doc/trpl/intermediate.md create mode 100644 src/doc/trpl/learn-rust.md create mode 100644 src/doc/trpl/lifetimes.md create mode 100644 src/doc/trpl/lol.txt delete mode 100644 src/doc/trpl/looping.md delete mode 100644 src/doc/trpl/more-strings.md create mode 100644 src/doc/trpl/move-semantics.md create mode 100644 src/doc/trpl/mutability.md rename src/doc/trpl/{unstable.md => nightly-rust.md} (100%) create mode 100644 src/doc/trpl/operators-and-overloading.md delete mode 100644 src/doc/trpl/pointers.md create mode 100644 src/doc/trpl/primitive-types.md create mode 100644 src/doc/trpl/references-and-borrowing.md create mode 100644 src/doc/trpl/slices.md delete mode 100644 src/doc/trpl/static-and-dynamic-dispatch.md create mode 100644 src/doc/trpl/static.md create mode 100644 src/doc/trpl/structs.md create mode 100644 src/doc/trpl/syntax-and-semantics.md create mode 100644 src/doc/trpl/the-stack-and-the-heap.md delete mode 100644 src/doc/trpl/tracing-macros.md create mode 100644 src/doc/trpl/trait-objects.md create mode 100644 src/doc/trpl/tuple-structs.md create mode 100644 src/doc/trpl/tuples.md create mode 100644 src/doc/trpl/type-aliases.md create mode 100644 src/doc/trpl/ufcs.md create mode 100644 src/doc/trpl/unsafe-code.md delete mode 100644 src/doc/trpl/unsafe.md create mode 100644 src/doc/trpl/unsized-types.md create mode 100644 src/doc/trpl/vectors.md create mode 100644 src/doc/trpl/while-loops.md diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 11e62aff42f3f..c9ac638098bdc 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -1,41 +1,63 @@ # Summary -* [The Basics](basic.md) +* [Getting Started](getting-started.md) * [Installing Rust](installing-rust.md) * [Hello, world!](hello-world.md) * [Hello, Cargo!](hello-cargo.md) +* [Learn Rust](learn-rust.md) +* [Effective Rust](effective-rust.md) + * [The Stack and the Heap](the-stack-and-the-heap.md) + * [`Debug` and `Display`](debug-and-display.md) + * [Testing](testing.md) + * [Documentation](documentation.md) + * [Iterators](iterators.md) + * [Concurrency](concurrency.md) + * [Error Handling](error-handling.md) + * [FFI](ffi.md) + * [`Deref` coercions](deref-coercions.md) +* [Syntax and Semantics](syntax-and-semantics.md) * [Variable Bindings](variable-bindings.md) - * [If](if.md) + * [Primitive Types](primitive-types.md) * [Functions](functions.md) * [Comments](comments.md) - * [Compound Data Types](compound-data-types.md) + * [Structs](structs.md) + * [Mutability](mutability.md) + * [Method Syntax](method-syntax.md) + * [Enums](enums.md) + * [`if`](if.md) * [Match](match.md) - * [Looping](looping.md) + * [Patterns](patterns.md) + * [`for` loops](for-loops.md) + * [`while` loops](while-loops.md) + * [Ownership](ownership.md) + * [References and Borrowing](references-and-borrowing.md) + * [Lifetimes](lifetimes.md) + * [Move semantics](move-semantics.md) + * [Drop](drop.md) + * [Vectors](vectors.md) + * [Arrays](arrays.md) + * [Slices](slices.md) * [Strings](strings.md) - * [Arrays, Vectors, and Slices](arrays-vectors-and-slices.md) -* [Intermediate Rust](intermediate.md) + * [Traits](traits.md) + * [Operators and Overloading](operators-and-overloading.md) + * [Generics](generics.md) + * [Trait Objects](trait-objects.md) + * [Closures](closures.md) + * [Universal Function Call Syntax](ufcs.md) * [Crates and Modules](crates-and-modules.md) - * [Testing](testing.md) - * [Pointers](pointers.md) - * [Ownership](ownership.md) - * [More Strings](more-strings.md) - * [Patterns](patterns.md) - * [Method Syntax](method-syntax.md) + * [`static`](static.md) + * [`const`](const.md) + * [Tuples](tuples.md) + * [Tuple Structs](tuple-structs.md) + * [Attributes](attributes.md) + * [Conditional Compilation](conditional-compilation.md) + * [`type` aliases](type-aliases.md) + * [Casting between types](casting-between-types.md) * [Associated Types](associated-types.md) - * [Closures](closures.md) - * [Iterators](iterators.md) - * [Generics](generics.md) - * [Traits](traits.md) - * [Static and Dynamic Dispatch](static-and-dynamic-dispatch.md) + * [Unsized Types](unsized-types.md) * [Macros](macros.md) - * [Concurrency](concurrency.md) - * [Error Handling](error-handling.md) - * [Documentation](documentation.md) -* [Advanced Topics](advanced.md) - * [FFI](ffi.md) - * [Unsafe Code](unsafe.md) - * [Advanced Macros](advanced-macros.md) -* [Unstable Rust](unstable.md) + * [`unsafe` Code](unsafe-code.md) +* [Nightly Rust](nightly-rust.md) * [Compiler Plugins](plugins.md) * [Inline Assembly](inline-assembly.md) * [No stdlib](no-stdlib.md) @@ -44,5 +66,4 @@ * [Link args](link-args.md) * [Benchmark Tests](benchmark-tests.md) * [Box Syntax and Patterns](box-syntax-and-patterns.md) -* [Conclusion](conclusion.md) * [Glossary](glossary.md) diff --git a/src/doc/trpl/advanced-macros.md b/src/doc/trpl/advanced-macros.md deleted file mode 100644 index fef458caaaf33..0000000000000 --- a/src/doc/trpl/advanced-macros.md +++ /dev/null @@ -1,242 +0,0 @@ -% Advanced macros - -This chapter picks up where the [introductory macro chapter](macros.html) left -off. - -# Syntactic requirements - -Even when Rust code contains un-expanded macros, it can be parsed as a full -[syntax tree][ast]. This property can be very useful for editors and other -tools that process code. It also has a few consequences for the design of -Rust's macro system. - -[ast]: glossary.html#abstract-syntax-tree - -One consequence is that Rust must determine, when it parses a macro invocation, -whether the macro stands in for - -* zero or more items, -* zero or more methods, -* an expression, -* a statement, or -* a pattern. - -A macro invocation within a block could stand for some items, or for an -expression / statement. Rust uses a simple rule to resolve this ambiguity. A -macro invocation that stands for items must be either - -* delimited by curly braces, e.g. `foo! { ... }`, or -* terminated by a semicolon, e.g. `foo!(...);` - -Another consequence of pre-expansion parsing is that the macro invocation must -consist of valid Rust tokens. Furthermore, parentheses, brackets, and braces -must be balanced within a macro invocation. For example, `foo!([)` is -forbidden. This allows Rust to know where the macro invocation ends. - -More formally, the macro invocation body must be a sequence of *token trees*. -A token tree is defined recursively as either - -* a sequence of token trees surrounded by matching `()`, `[]`, or `{}`, or -* any other single token. - -Within a matcher, each metavariable has a *fragment specifier*, identifying -which syntactic form it matches. - -* `ident`: an identifier. Examples: `x`; `foo`. -* `path`: a qualified name. Example: `T::SpecialA`. -* `expr`: an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`; `f(42)`. -* `ty`: a type. Examples: `i32`; `Vec<(char, String)>`; `&T`. -* `pat`: a pattern. Examples: `Some(t)`; `(17, 'a')`; `_`. -* `stmt`: a single statement. Example: `let x = 3`. -* `block`: a brace-delimited sequence of statements. Example: - `{ log(error, "hi"); return 12; }`. -* `item`: an [item][]. Examples: `fn foo() { }`; `struct Bar;`. -* `meta`: a "meta item", as found in attributes. Example: `cfg(target_os = "windows")`. -* `tt`: a single token tree. - -There are additional rules regarding the next token after a metavariable: - -* `expr` variables must be followed by one of: `=> , ;` -* `ty` and `path` variables must be followed by one of: `=> , : = > as` -* `pat` variables must be followed by one of: `=> , =` -* Other variables may be followed by any token. - -These rules provide some flexibility for Rust's syntax to evolve without -breaking existing macros. - -The macro system does not deal with parse ambiguity at all. For example, the -grammar `$($t:ty)* $e:expr` will always fail to parse, because the parser would -be forced to choose between parsing `$t` and parsing `$e`. Changing the -invocation syntax to put a distinctive token in front can solve the problem. In -this case, you can write `$(T $t:ty)* E $e:exp`. - -[item]: ../reference.html#items - -# Scoping and macro import/export - -Macros are expanded at an early stage in compilation, before name resolution. -One downside is that scoping works differently for macros, compared to other -constructs in the language. - -Definition and expansion of macros both happen in a single depth-first, -lexical-order traversal of a crate's source. So a macro defined at module scope -is visible to any subsequent code in the same module, which includes the body -of any subsequent child `mod` items. - -A macro defined within the body of a single `fn`, or anywhere else not at -module scope, is visible only within that item. - -If a module has the `macro_use` attribute, its macros are also visible in its -parent module after the child's `mod` item. If the parent also has `macro_use` -then the macros will be visible in the grandparent after the parent's `mod` -item, and so forth. - -The `macro_use` attribute can also appear on `extern crate`. In this context -it controls which macros are loaded from the external crate, e.g. - -```rust,ignore -#[macro_use(foo, bar)] -extern crate baz; -``` - -If the attribute is given simply as `#[macro_use]`, all macros are loaded. If -there is no `#[macro_use]` attribute then no macros are loaded. Only macros -defined with the `#[macro_export]` attribute may be loaded. - -To load a crate's macros *without* linking it into the output, use `#[no_link]` -as well. - -An example: - -```rust -macro_rules! m1 { () => (()) } - -// visible here: m1 - -mod foo { - // visible here: m1 - - #[macro_export] - macro_rules! m2 { () => (()) } - - // visible here: m1, m2 -} - -// visible here: m1 - -macro_rules! m3 { () => (()) } - -// visible here: m1, m3 - -#[macro_use] -mod bar { - // visible here: m1, m3 - - macro_rules! m4 { () => (()) } - - // visible here: m1, m3, m4 -} - -// visible here: m1, m3, m4 -# fn main() { } -``` - -When this library is loaded with `#[macro_use] extern crate`, only `m2` will -be imported. - -The Rust Reference has a [listing of macro-related -attributes](../reference.html#macro--and-plugin-related-attributes). - -# The variable `$crate` - -A further difficulty occurs when a macro is used in multiple crates. Say that -`mylib` defines - -```rust -pub fn increment(x: u32) -> u32 { - x + 1 -} - -#[macro_export] -macro_rules! inc_a { - ($x:expr) => ( ::increment($x) ) -} - -#[macro_export] -macro_rules! inc_b { - ($x:expr) => ( ::mylib::increment($x) ) -} -# fn main() { } -``` - -`inc_a` only works within `mylib`, while `inc_b` only works outside the -library. Furthermore, `inc_b` will break if the user imports `mylib` under -another name. - -Rust does not (yet) have a hygiene system for crate references, but it does -provide a simple workaround for this problem. Within a macro imported from a -crate named `foo`, the special macro variable `$crate` will expand to `::foo`. -By contrast, when a macro is defined and then used in the same crate, `$crate` -will expand to nothing. This means we can write - -```rust -#[macro_export] -macro_rules! inc { - ($x:expr) => ( $crate::increment($x) ) -} -# fn main() { } -``` - -to define a single macro that works both inside and outside our library. The -function name will expand to either `::increment` or `::mylib::increment`. - -To keep this system simple and correct, `#[macro_use] extern crate ...` may -only appear at the root of your crate, not inside `mod`. This ensures that -`$crate` is a single identifier. - -# The deep end - -The introductory chapter mentioned recursive macros, but it did not give the -full story. Recursive macros are useful for another reason: Each recursive -invocation gives you another opportunity to pattern-match the macro's -arguments. - -As an extreme example, it is possible, though hardly advisable, to implement -the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton -within Rust's macro system. - -```rust -macro_rules! bct { - // cmd 0: d ... => ... - (0, $($ps:tt),* ; $_d:tt) - => (bct!($($ps),*, 0 ; )); - (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*) - => (bct!($($ps),*, 0 ; $($ds),*)); - - // cmd 1p: 1 ... => 1 ... p - (1, $p:tt, $($ps:tt),* ; 1) - => (bct!($($ps),*, 1, $p ; 1, $p)); - (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*) - => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p)); - - // cmd 1p: 0 ... => 0 ... - (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) - => (bct!($($ps),*, 1, $p ; $($ds),*)); - - // halt on empty data string - ( $($ps:tt),* ; ) - => (()); -} -``` - -Exercise: use macros to reduce duplication in the above definition of the -`bct!` macro. - -# Procedural macros - -If Rust's macro system can't do what you need, you may want to write a -[compiler plugin](plugins.html) instead. Compared to `macro_rules!` -macros, this is significantly more work, the interfaces are much less stable, -and bugs can be much harder to track down. In exchange you get the -flexibility of running arbitrary Rust code within the compiler. Syntax -extension plugins are sometimes called *procedural macros* for this reason. diff --git a/src/doc/trpl/advanced.md b/src/doc/trpl/advanced.md deleted file mode 100644 index 447a8a614bf56..0000000000000 --- a/src/doc/trpl/advanced.md +++ /dev/null @@ -1,8 +0,0 @@ -% Advanced - -In a similar fashion to "Intermediate," this section is full of individual, -deep-dive chapters, which stand alone and can be read in any order. These -chapters focus on the most complex features, as well as some things that -are only available in upcoming versions of Rust. - -After reading "Advanced," you'll be a Rust expert! diff --git a/src/doc/trpl/arrays-vectors-and-slices.md b/src/doc/trpl/arrays-vectors-and-slices.md deleted file mode 100644 index 2916dca2c06b0..0000000000000 --- a/src/doc/trpl/arrays-vectors-and-slices.md +++ /dev/null @@ -1,102 +0,0 @@ -% Arrays, Vectors, and Slices - -Like many programming languages, Rust has list types to represent a sequence of -things. The most basic is the *array*, a fixed-size list of elements of the -same type. By default, arrays are immutable. - -```{rust} -let a = [1, 2, 3]; // a: [i32; 3] -let mut m = [1, 2, 3]; // mut m: [i32; 3] -``` - -There's a shorthand for initializing each element of an array to the same -value. In this example, each element of `a` will be initialized to `0`: - -```{rust} -let a = [0; 20]; // a: [i32; 20] -``` - -Arrays have type `[T; N]`. We'll talk about this `T` notation later, when we -cover generics. - -You can get the number of elements in an array `a` with `a.len()`, and use -`a.iter()` to iterate over them with a for loop. This code will print each -number in order: - -```{rust} -let a = [1, 2, 3]; - -println!("a has {} elements", a.len()); -for e in a.iter() { - println!("{}", e); -} -``` - -You can access a particular element of an array with *subscript notation*: - -```{rust} -let names = ["Graydon", "Brian", "Niko"]; // names: [&str; 3] - -println!("The second name is: {}", names[1]); -``` - -Subscripts start at zero, like in most programming languages, so the first name -is `names[0]` and the second name is `names[1]`. The above example prints -`The second name is: Brian`. If you try to use a subscript that is not in the -array, you will get an error: array access is bounds-checked at run-time. Such -errant access is the source of many bugs in other systems programming -languages. - -A *vector* is a dynamic or "growable" array, implemented as the standard -library type [`Vec`](../std/vec/) (we'll talk about what the `` means -later). Vectors always allocate their data on the heap. Vectors are to slices -what `String` is to `&str`. You can create them with the `vec!` macro: - -```{rust} -let v = vec![1, 2, 3]; // v: Vec -``` - -(Notice that unlike the `println!` macro we've used in the past, we use square -brackets `[]` with `vec!`. Rust allows you to use either in either situation, -this is just convention.) - -There's an alternate form of `vec!` for repeating an initial value: - -``` -let v = vec![0; 10]; // ten zeroes -``` - -You can get the length of, iterate over, and subscript vectors just like -arrays. In addition, (mutable) vectors can grow automatically: - -```{rust} -let mut nums = vec![1, 2, 3]; // mut nums: Vec - -nums.push(4); - -println!("The length of nums is now {}", nums.len()); // Prints 4 -``` - -Vectors have many more useful methods. - -A *slice* is a reference to (or "view" into) an array. They are useful for -allowing safe, efficient access to a portion of an array without copying. For -example, you might want to reference just one line of a file read into memory. -By nature, a slice is not created directly, but from an existing variable. -Slices have a length, can be mutable or not, and in many ways behave like -arrays: - -```{rust} -let a = [0, 1, 2, 3, 4]; -let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3 - -for e in middle.iter() { - println!("{}", e); // Prints 1, 2, 3 -} -``` - -You can also take a slice of a vector, `String`, or `&str`, because they are -backed by arrays. Slices have type `&[T]`, which we'll talk about when we cover -generics. - -We have now learned all of the most basic Rust concepts. diff --git a/src/doc/trpl/arrays.md b/src/doc/trpl/arrays.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/associated-types.md b/src/doc/trpl/associated-types.md index 7161cd33f89be..e69de29bb2d1d 100644 --- a/src/doc/trpl/associated-types.md +++ b/src/doc/trpl/associated-types.md @@ -1,202 +0,0 @@ -% Associated Types - -Associated types are a powerful part of Rust's type system. They're related to -the idea of a 'type family', in other words, grouping multiple types together. That -description is a bit abstract, so let's dive right into an example. If you want -to write a `Graph` trait, you have two types to be generic over: the node type -and the edge type. So you might write a trait, `Graph`, that looks like -this: - -```rust -trait Graph { - fn has_edge(&self, &N, &N) -> bool; - fn edges(&self, &N) -> Vec; - // etc -} -``` - -While this sort of works, it ends up being awkward. For example, any function -that wants to take a `Graph` as a parameter now _also_ needs to be generic over -the `N`ode and `E`dge types too: - -```rust,ignore -fn distance>(graph: &G, start: &N, end: &N) -> u32 { ... } -``` - -Our distance calculation works regardless of our `Edge` type, so the `E` stuff in -this signature is just a distraction. - -What we really want to say is that a certain `E`dge and `N`ode type come together -to form each kind of `Graph`. We can do that with associated types: - -```rust -trait Graph { - type N; - type E; - - fn has_edge(&self, &Self::N, &Self::N) -> bool; - fn edges(&self, &Self::N) -> Vec; - // etc -} -``` - -Now, our clients can be abstract over a given `Graph`: - -```rust,ignore -fn distance(graph: &G, start: &G::N, end: &G::N) -> uint { ... } -``` - -No need to deal with the `E`dge type here! - -Let's go over all this in more detail. - -## Defining associated types - -Let's build that `Graph` trait. Here's the definition: - -```rust -trait Graph { - type N; - type E; - - fn has_edge(&self, &Self::N, &Self::N) -> bool; - fn edges(&self, &Self::N) -> Vec; -} -``` - -Simple enough. Associated types use the `type` keyword, and go inside the body -of the trait, with the functions. - -These `type` declarations can have all the same thing as functions do. For example, -if we wanted our `N` type to implement `Display`, so we can print the nodes out, -we could do this: - -```rust -use std::fmt; - -trait Graph { - type N: fmt::Display; - type E; - - fn has_edge(&self, &Self::N, &Self::N) -> bool; - fn edges(&self, &Self::N) -> Vec; -} -``` - -## Implementing associated types - -Just like any trait, traits that use associated types use the `impl` keyword to -provide implementations. Here's a simple implementation of Graph: - -```rust -# trait Graph { -# type N; -# type E; -# fn has_edge(&self, &Self::N, &Self::N) -> bool; -# fn edges(&self, &Self::N) -> Vec; -# } -struct Node; - -struct Edge; - -struct MyGraph; - -impl Graph for MyGraph { - type N = Node; - type E = Edge; - - fn has_edge(&self, n1: &Node, n2: &Node) -> bool { - true - } - - fn edges(&self, n: &Node) -> Vec { - Vec::new() - } -} -``` - -This silly implementation always returns `true` and an empty `Vec`, but it -gives you an idea of how to implement this kind of thing. We first need three -`struct`s, one for the graph, one for the node, and one for the edge. If it made -more sense to use a different type, that would work as well, we're just going to -use `struct`s for all three here. - -Next is the `impl` line, which is just like implementing any other trait. - -From here, we use `=` to define our associated types. The name the trait uses -goes on the left of the `=`, and the concrete type we're `impl`ementing this -for goes on the right. Finally, we use the concrete types in our function -declarations. - -## Trait objects with associated types - -There’s one more bit of syntax we should talk about: trait objects. If you -try to create a trait object from an associated type, like this: - -```rust,ignore -# trait Graph { -# type N; -# type E; -# fn has_edge(&self, &Self::N, &Self::N) -> bool; -# fn edges(&self, &Self::N) -> Vec; -# } -# struct Node; -# struct Edge; -# struct MyGraph; -# impl Graph for MyGraph { -# type N = Node; -# type E = Edge; -# fn has_edge(&self, n1: &Node, n2: &Node) -> bool { -# true -# } -# fn edges(&self, n: &Node) -> Vec { -# Vec::new() -# } -# } -let graph = MyGraph; -let obj = Box::new(graph) as Box; -``` - -You’ll get two errors: - -```text -error: the value of the associated type `E` (from the trait `main::Graph`) must -be specified [E0191] -let obj = Box::new(graph) as Box; - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -24:44 error: the value of the associated type `N` (from the trait -`main::Graph`) must be specified [E0191] -let obj = Box::new(graph) as Box; - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -``` - -We can’t create a trait object like this, because we don’t know the associated -types. Instead, we can write this: - -```rust -# trait Graph { -# type N; -# type E; -# fn has_edge(&self, &Self::N, &Self::N) -> bool; -# fn edges(&self, &Self::N) -> Vec; -# } -# struct Node; -# struct Edge; -# struct MyGraph; -# impl Graph for MyGraph { -# type N = Node; -# type E = Edge; -# fn has_edge(&self, n1: &Node, n2: &Node) -> bool { -# true -# } -# fn edges(&self, n: &Node) -> Vec { -# Vec::new() -# } -# } -let graph = MyGraph; -let obj = Box::new(graph) as Box>; -``` - -The `N=Node` syntax allows us to provide a concrete type, `Node`, for the `N` -type parameter. Same with `E=Edge`. If we didn’t proide this constraint, we -couldn’t be sure which `impl` to match this trait object to. diff --git a/src/doc/trpl/attributes.md b/src/doc/trpl/attributes.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/basic.md b/src/doc/trpl/basic.md deleted file mode 100644 index c267830e6e0d0..0000000000000 --- a/src/doc/trpl/basic.md +++ /dev/null @@ -1,7 +0,0 @@ -% Basics - -This section is a linear introduction to the basic syntax and semantics of -Rust. It has individual sections on each part of Rust's syntax. - -After reading "Basics," you will have a good foundation to learn more about -Rust, and can write very simple programs. diff --git a/src/doc/trpl/benchmark-tests.md b/src/doc/trpl/benchmark-tests.md index 890a2f8ae7de7..e69de29bb2d1d 100644 --- a/src/doc/trpl/benchmark-tests.md +++ b/src/doc/trpl/benchmark-tests.md @@ -1,152 +0,0 @@ -% Benchmark tests - -Rust supports benchmark tests, which can test the performance of your -code. Let's make our `src/lib.rs` look like this (comments elided): - -```{rust,ignore} -#![feature(test)] - -extern crate test; - -pub fn add_two(a: i32) -> i32 { - a + 2 -} - -#[cfg(test)] -mod test { - use super::*; - use test::Bencher; - - #[test] - fn it_works() { - assert_eq!(4, add_two(2)); - } - - #[bench] - fn bench_add_two(b: &mut Bencher) { - b.iter(|| add_two(2)); - } -} -``` - -Note the `test` feature gate, which enables this unstable feature. - -We've imported the `test` crate, which contains our benchmarking support. -We have a new function as well, with the `bench` attribute. Unlike regular -tests, which take no arguments, benchmark tests take a `&mut Bencher`. This -`Bencher` provides an `iter` method, which takes a closure. This closure -contains the code we'd like to benchmark. - -We can run benchmark tests with `cargo bench`: - -```bash -$ cargo bench - Compiling adder v0.0.1 (file:///home/steve/tmp/adder) - Running target/release/adder-91b3e234d4ed382a - -running 2 tests -test tests::it_works ... ignored -test tests::bench_add_two ... bench: 1 ns/iter (+/- 0) - -test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured -``` - -Our non-benchmark test was ignored. You may have noticed that `cargo bench` -takes a bit longer than `cargo test`. This is because Rust runs our benchmark -a number of times, and then takes the average. Because we're doing so little -work in this example, we have a `1 ns/iter (+/- 0)`, but this would show -the variance if there was one. - -Advice on writing benchmarks: - - -* Move setup code outside the `iter` loop; only put the part you want to measure inside -* Make the code do "the same thing" on each iteration; do not accumulate or change state -* Make the outer function idempotent too; the benchmark runner is likely to run - it many times -* Make the inner `iter` loop short and fast so benchmark runs are fast and the - calibrator can adjust the run-length at fine resolution -* Make the code in the `iter` loop do something simple, to assist in pinpointing - performance improvements (or regressions) - -## Gotcha: optimizations - -There's another tricky part to writing benchmarks: benchmarks compiled with -optimizations activated can be dramatically changed by the optimizer so that -the benchmark is no longer benchmarking what one expects. For example, the -compiler might recognize that some calculation has no external effects and -remove it entirely. - -```{rust,ignore} -#![feature(test)] - -extern crate test; -use test::Bencher; - -#[bench] -fn bench_xor_1000_ints(b: &mut Bencher) { - b.iter(|| { - (0..1000).fold(0, |old, new| old ^ new); - }); -} -``` - -gives the following results - -```text -running 1 test -test bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0) - -test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured -``` - -The benchmarking runner offers two ways to avoid this. Either, the closure that -the `iter` method receives can return an arbitrary value which forces the -optimizer to consider the result used and ensures it cannot remove the -computation entirely. This could be done for the example above by adjusting the -`b.iter` call to - -```rust -# struct X; -# impl X { fn iter(&self, _: F) where F: FnMut() -> T {} } let b = X; -b.iter(|| { - // note lack of `;` (could also use an explicit `return`). - (0..1000).fold(0, |old, new| old ^ new) -}); -``` - -Or, the other option is to call the generic `test::black_box` function, which -is an opaque "black box" to the optimizer and so forces it to consider any -argument as used. - -```rust -#![feature(test)] - -extern crate test; - -# fn main() { -# struct X; -# impl X { fn iter(&self, _: F) where F: FnMut() -> T {} } let b = X; -b.iter(|| { - let n = test::black_box(1000); - - (0..n).fold(0, |a, b| a ^ b) -}) -# } -``` - -Neither of these read or modify the value, and are very cheap for small values. -Larger values can be passed indirectly to reduce overhead (e.g. -`black_box(&huge_struct)`). - -Performing either of the above changes gives the following benchmarking results - -```text -running 1 test -test bench_xor_1000_ints ... bench: 131 ns/iter (+/- 3) - -test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured -``` - -However, the optimizer can still modify a testcase in an undesirable manner -even when using either of the above. diff --git a/src/doc/trpl/box-syntax-and-patterns.md b/src/doc/trpl/box-syntax-and-patterns.md index 839f07d984322..e69de29bb2d1d 100644 --- a/src/doc/trpl/box-syntax-and-patterns.md +++ b/src/doc/trpl/box-syntax-and-patterns.md @@ -1,100 +0,0 @@ -% Box Syntax and Patterns - -Currently the only stable way to create a `Box` is via the `Box::new` method. -Also it is not possible in stable Rust to destructure a `Box` in a match -pattern. The unstable `box` keyword can be used to both create and destructure -a `Box`. An example usage would be: - -``` -#![feature(box_syntax, box_patterns)] - -fn main() { - let b = Some(box 5); - match b { - Some(box n) if n < 0 => { - println!("Box contains negative number {}", n); - }, - Some(box n) if n >= 0 => { - println!("Box contains non-negative number {}", n); - }, - None => { - println!("No box"); - }, - _ => unreachable!() - } -} -``` - -Note that these features are currently hidden behind the `box_syntax` (box -creation) and `box_patterns` (destructuring and pattern matching) gates -because the syntax may still change in the future. - -# Returning Pointers - -In many languages with pointers, you'd return a pointer from a function -so as to avoid copying a large data structure. For example: - -```{rust} -struct BigStruct { - one: i32, - two: i32, - // etc - one_hundred: i32, -} - -fn foo(x: Box) -> Box { - Box::new(*x) -} - -fn main() { - let x = Box::new(BigStruct { - one: 1, - two: 2, - one_hundred: 100, - }); - - let y = foo(x); -} -``` - -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`. - -This is an antipattern in Rust. Instead, write this: - -```rust -#![feature(box_syntax)] - -struct BigStruct { - one: i32, - two: i32, - // etc - one_hundred: i32, -} - -fn foo(x: Box) -> BigStruct { - *x -} - -fn main() { - let x = Box::new(BigStruct { - one: 1, - two: 2, - one_hundred: 100, - }); - - let y: Box = box foo(x); -} -``` - -This gives you flexibility without sacrificing performance. - -You may think that this gives us terrible performance: return a value and then -immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is -smarter than that. There is no copy in this code. `main` allocates enough room -for the `box`, passes a pointer to that memory into `foo` as `x`, and then -`foo` writes the value straight into the `Box`. - -This is important enough that it bears repeating: pointers are not for -optimizing returning values from your code. Allow the caller to choose how they -want to use your output. diff --git a/src/doc/trpl/casting-between-types.md b/src/doc/trpl/casting-between-types.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/closures.md b/src/doc/trpl/closures.md index e63331e5206bf..e69de29bb2d1d 100644 --- a/src/doc/trpl/closures.md +++ b/src/doc/trpl/closures.md @@ -1,475 +0,0 @@ -% Closures - -Rust not only has named functions, but anonymous functions as well. Anonymous -functions that have an associated environment are called 'closures', because they -close over an environment. Rust has a really great implementation of them, as -we'll see. - -# Syntax - -Closures look like this: - -```rust -let plus_one = |x: i32| x + 1; - -assert_eq!(2, plus_one(1)); -``` - -We create a binding, `plus_one`, and assign it to a closure. The closure's -arguments go between the pipes (`|`), and the body is an expression, in this -case, `x + 1`. Remember that `{ }` is an expression, so we can have multi-line -closures too: - -```rust -let plus_two = |x| { - let mut result: i32 = x; - - result += 1; - result += 1; - - result -}; - -assert_eq!(4, plus_two(2)); -``` - -You'll notice a few things about closures that are a bit different than regular -functions defined with `fn`. The first of which is that we did not need to -annotate the types of arguments the closure takes or the values it returns. We -can: - -```rust -let plus_one = |x: i32| -> i32 { x + 1 }; - -assert_eq!(2, plus_one(1)); -``` - -But we don't have to. Why is this? Basically, it was chosen for ergonomic reasons. -While specifying the full type for named functions is helpful with things like -documentation and type inference, the types of closures are rarely documented -since they’re anonymous, and they don’t cause the kinds of error-at-a-distance -that inferring named function types can. - -The second is that the syntax is similar, but a bit different. I've added spaces -here to make them look a little closer: - -```rust -fn plus_one_v1 (x: i32 ) -> i32 { x + 1 } -let plus_one_v2 = |x: i32 | -> i32 { x + 1 }; -let plus_one_v3 = |x: i32 | x + 1 ; -``` - -Small differences, but they're similar in ways. - -# Closures and their environment - -Closures are called such because they 'close over their environment.' It -looks like this: - -```rust -let num = 5; -let plus_num = |x: i32| x + num; - -assert_eq!(10, plus_num(5)); -``` - -This closure, `plus_num`, refers to a `let` binding in its scope: `num`. More -specifically, it borrows the binding. If we do something that would conflict -with that binding, we get an error. Like this one: - -```rust,ignore -let mut num = 5; -let plus_num = |x: i32| x + num; - -let y = &mut num; -``` - -Which errors with: - -```text -error: cannot borrow `num` as mutable because it is also borrowed as immutable - let y = &mut num; - ^~~ -note: previous borrow of `num` occurs here due to use in closure; the immutable - borrow prevents subsequent moves or mutable borrows of `num` until the borrow - ends - let plus_num = |x| x + num; - ^~~~~~~~~~~ -note: previous borrow ends here -fn main() { - let mut num = 5; - let plus_num = |x| x + num; - - let y = &mut num; -} -^ -``` - -A verbose yet helpful error message! As it says, we can't take a mutable borrow -on `num` because the closure is already borrowing it. If we let the closure go -out of scope, we can: - -```rust -let mut num = 5; -{ - let plus_num = |x: i32| x + num; - -} // plus_num goes out of scope, borrow of num ends - -let y = &mut num; -``` - -If your closure requires it, however, Rust will take ownership and move -the environment instead: - -```rust,ignore -let nums = vec![1, 2, 3]; - -let takes_nums = || nums; - -println!("{:?}", nums); -``` - -This gives us: - -```text -note: `nums` moved into closure environment here because it has type - `[closure(()) -> collections::vec::Vec]`, which is non-copyable -let takes_nums = || nums; - ^~~~~~~ -``` - -`Vec` has ownership over its contents, and therefore, when we refer to it -in our closure, we have to take ownership of `nums`. It's the same as if we'd -passed `nums` to a function that took ownership of it. - -## `move` closures - -We can force our closure to take ownership of its environment with the `move` -keyword: - -```rust -let num = 5; - -let owns_num = move |x: i32| x + num; -``` - -Now, even though the keyword is `move`, the variables follow normal move semantics. -In this case, `5` implements `Copy`, and so `owns_num` takes ownership of a copy -of `num`. So what's the difference? - -```rust -let mut num = 5; - -{ - let mut add_num = |x: i32| num += x; - - add_num(5); -} - -assert_eq!(10, num); -``` - -So in this case, our closure took a mutable reference to `num`, and then when -we called `add_num`, it mutated the underlying value, as we'd expect. We also -needed to declare `add_num` as `mut` too, because we’re mutating its -environment. - -If we change to a `move` closure, it's different: - -```rust -let mut num = 5; - -{ - let mut add_num = move |x: i32| num += x; - - add_num(5); -} - -assert_eq!(5, num); -``` - -We only get `5`. Rather than taking a mutable borrow out on our `num`, we took -ownership of a copy. - -Another way to think about `move` closures: they give a closure its own stack -frame. Without `move`, a closure may be tied to the stack frame that created -it, while a `move` closure is self-contained. This means that you cannot -generally return a non-`move` closure from a function, for example. - -But before we talk about taking and returning closures, we should talk some more -about the way that closures are implemented. As a systems language, Rust gives -you tons of control over what your code does, and closures are no different. - -# Closure implementation - -Rust's implementation of closures is a bit different than other languages. They -are effectively syntax sugar for traits. You'll want to make sure to have read -the [traits chapter][traits] before this one, as well as the chapter on [static -and dynamic dispatch][dispatch], which talks about trait objects. - -[traits]: traits.html -[dispatch]: static-and-dynamic-dispatch.html - -Got all that? Good. - -The key to understanding how closures work under the hood is something a bit -strange: Using `()` to call a function, like `foo()`, is an overloadable -operator. From this, everything else clicks into place. In Rust, we use the -trait system to overload operators. Calling functions is no different. We have -three separate traits to overload with: - -```rust -# mod foo { -pub trait Fn : FnMut { - extern "rust-call" fn call(&self, args: Args) -> Self::Output; -} - -pub trait FnMut : FnOnce { - extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; -} - -pub trait FnOnce { - type Output; - - extern "rust-call" fn call_once(self, args: Args) -> Self::Output; -} -# } -``` - -You'll notice a few differences between these traits, but a big one is `self`: -`Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This -covers all three kinds of `self` via the usual method call syntax. But we've -split them up into three traits, rather than having a single one. This gives us -a large amount of control over what kind of closures we can take. - -The `|| {}` syntax for closures is sugar for these three traits. Rust will -generate a struct for the environment, `impl` the appropriate trait, and then -use it. - -# Taking closures as arguments - -Now that we know that closures are traits, we already know how to accept and -return closures: just like any other trait! - -This also means that we can choose static vs dynamic dispatch as well. First, -let's write a function which takes something callable, calls it, and returns -the result: - -```rust -fn call_with_one(some_closure: F) -> i32 - where F : Fn(i32) -> i32 { - - some_closure(1) -} - -let answer = call_with_one(|x| x + 2); - -assert_eq!(3, answer); -``` - -We pass our closure, `|x| x + 2`, to `call_with_one`. It just does what it -suggests: it calls the closure, giving it `1` as an argument. - -Let's examine the signature of `call_with_one` in more depth: - -```rust -fn call_with_one(some_closure: F) -> i32 -# where F : Fn(i32) -> i32 { -# some_closure(1) } -``` - -We take one parameter, and it has the type `F`. We also return a `i32`. This part -isn't interesting. The next part is: - -```rust -# fn call_with_one(some_closure: F) -> i32 - where F : Fn(i32) -> i32 { -# some_closure(1) } -``` - -Because `Fn` is a trait, we can bound our generic with it. In this case, our closure -takes a `i32` as an argument and returns an `i32`, and so the generic bound we use -is `Fn(i32) -> i32`. - -There's one other key point here: because we're bounding a generic with a -trait, this will get monomorphized, and therefore, we'll be doing static -dispatch into the closure. That's pretty neat. In many langauges, closures are -inherently heap allocated, and will always involve dynamic dispatch. In Rust, -we can stack allocate our closure environment, and statically dispatch the -call. This happens quite often with iterators and their adapters, which often -take closures as arguments. - -Of course, if we want dynamic dispatch, we can get that too. A trait object -handles this case, as usual: - -```rust -fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 { - some_closure(1) -} - -let answer = call_with_one(&|x| x + 2); - -assert_eq!(3, answer); -``` - -Now we take a trait object, a `&Fn`. And we have to make a reference -to our closure when we pass it to `call_with_one`, so we use `&||`. - -# Returning closures - -It’s very common for functional-style code to return closures in various -situations. If you try to return a closure, you may run into an error. At -first, it may seem strange, but we'll figure it out. Here's how you'd probably -try to return a closure from a function: - -```rust,ignore -fn factory() -> (Fn(i32) -> Vec) { - let vec = vec![1, 2, 3]; - - |n| vec.push(n) -} - -let f = factory(); - -let answer = f(4); -assert_eq!(vec![1, 2, 3, 4], answer); -``` - -This gives us these long, related errors: - -```text -error: the trait `core::marker::Sized` is not implemented for the type -`core::ops::Fn(i32) -> collections::vec::Vec` [E0277] -f = factory(); -^ -note: `core::ops::Fn(i32) -> collections::vec::Vec` does not have a -constant size known at compile-time -f = factory(); -^ -error: the trait `core::marker::Sized` is not implemented for the type -`core::ops::Fn(i32) -> collections::vec::Vec` [E0277] -factory() -> (Fn(i32) -> Vec) { - ^~~~~~~~~~~~~~~~~~~~~ -note: `core::ops::Fn(i32) -> collections::vec::Vec` does not have a constant size known at compile-time -fa ctory() -> (Fn(i32) -> Vec) { - ^~~~~~~~~~~~~~~~~~~~~ - -``` - -In order to return something from a function, Rust needs to know what -size the return type is. But since `Fn` is a trait, it could be various -things of various sizes: many different types can implement `Fn`. An easy -way to give something a size is to take a reference to it, as references -have a known size. So we'd write this: - -```rust,ignore -fn factory() -> &(Fn(i32) -> Vec) { - let vec = vec![1, 2, 3]; - - |n| vec.push(n) -} - -let f = factory(); - -let answer = f(4); -assert_eq!(vec![1, 2, 3, 4], answer); -``` - -But we get another error: - -```text -error: missing lifetime specifier [E0106] -fn factory() -> &(Fn(i32) -> i32) { - ^~~~~~~~~~~~~~~~~ -``` - -Right. Because we have a reference, we need to give it a lifetime. But -our `factory()` function takes no arguments, so elision doesn't kick in -here. What lifetime can we choose? `'static`: - -```rust,ignore -fn factory() -> &'static (Fn(i32) -> i32) { - let num = 5; - - |x| x + num -} - -let f = factory(); - -let answer = f(1); -assert_eq!(6, answer); -``` - -But we get another error: - -```text -error: mismatched types: - expected `&'static core::ops::Fn(i32) -> i32`, - found `[closure :7:9: 7:20]` -(expected &-ptr, - found closure) [E0308] - |x| x + num - ^~~~~~~~~~~ - -``` - -This error is letting us know that we don't have a `&'static Fn(i32) -> i32`, -we have a `[closure :7:9: 7:20]`. Wait, what? - -Because each closure generates its own environment `struct` and implementation -of `Fn` and friends, these types are anonymous. They exist just solely for -this closure. So Rust shows them as `closure `, rather than some -autogenerated name. - -But why doesn't our closure implement `&'static Fn`? Well, as we discussed before, -closures borrow their environment. And in this case, our environment is based -on a stack-allocated `5`, the `num` variable binding. So the borrow has a lifetime -of the stack frame. So if we returned this closure, the function call would be -over, the stack frame would go away, and our closure is capturing an environment -of garbage memory! - -So what to do? This _almost_ works: - -```rust,ignore -fn factory() -> Box i32> { - let num = 5; - - Box::new(|x| x + num) -} -# fn main() { -let f = factory(); - -let answer = f(1); -assert_eq!(6, answer); -# } -``` - -We use a trait object, by `Box`ing up the `Fn`. There's just one last problem: - -```text -error: `num` does not live long enough -Box::new(|x| x + num) - ^~~~~~~~~~~ -``` - -We still have a reference to the parent stack frame. With one last fix, we can -make this work: - -```rust -fn factory() -> Box i32> { - let num = 5; - - Box::new(move |x| x + num) -} -# fn main() { -let f = factory(); - -let answer = f(1); -assert_eq!(6, answer); -# } -``` - -By making the inner closure a `move Fn`, we create a new stack frame for our -closure. By `Box`ing it up, we've given it a known size, and allowing it to -escape our stack frame. diff --git a/src/doc/trpl/comments.md b/src/doc/trpl/comments.md index 441496e6a755b..e69de29bb2d1d 100644 --- a/src/doc/trpl/comments.md +++ b/src/doc/trpl/comments.md @@ -1,47 +0,0 @@ -% Comments - -Now that we have some functions, it's a good idea to learn about comments. -Comments are notes that you leave to other programmers to help explain things -about your code. The compiler mostly ignores them. - -Rust has two kinds of comments that you should care about: *line comments* -and *doc comments*. - -```{rust} -// Line comments are anything after '//' and extend to the end of the line. - -let x = 5; // this is also a line comment. - -// If you have a long explanation for something, you can put line comments next -// to each other. Put a space between the // and your comment so that it's -// more readable. -``` - -The other kind of comment is a doc comment. Doc comments use `///` instead of -`//`, and support Markdown notation inside: - -```{rust} -/// `hello` is a function that prints a greeting that is personalized based on -/// the name given. -/// -/// # Arguments -/// -/// * `name` - The name of the person you'd like to greet. -/// -/// # Examples -/// -/// ```rust -/// let name = "Steve"; -/// hello(name); // prints "Hello, Steve!" -/// ``` -fn hello(name: &str) { - println!("Hello, {}!", name); -} -``` - -When writing doc comments, adding sections for any arguments, return values, -and providing some examples of usage is very, very helpful. Don't worry about -the `&str`, we'll get to it soon. - -You can use the [`rustdoc`](documentation.html) tool to generate HTML documentation -from these doc comments. diff --git a/src/doc/trpl/compound-data-types.md b/src/doc/trpl/compound-data-types.md deleted file mode 100644 index e44d2edd667a1..0000000000000 --- a/src/doc/trpl/compound-data-types.md +++ /dev/null @@ -1,364 +0,0 @@ -% Compound Data Types - -Rust, like many programming languages, has a number of different data types -that are built-in. You've already done some simple work with integers and -strings, but next, let's talk about some more complicated ways of storing data. - -## Tuples - -The first compound data type we're going to talk about is called the *tuple*. -A tuple is an ordered list of fixed size. Like this: - -```rust -let x = (1, "hello"); -``` - -The parentheses and commas form this two-length tuple. Here's the same code, but -with the type annotated: - -```rust -let x: (i32, &str) = (1, "hello"); -``` - -As you can see, the type of a tuple looks just like the tuple, but with each -position having a type name rather than the value. Careful readers will also -note that tuples are heterogeneous: we have an `i32` and a `&str` in this tuple. -You have briefly seen `&str` used as a type before, and we'll discuss the -details of strings later. In systems programming languages, strings are a bit -more complex than in other languages. For now, just read `&str` as a *string -slice*, and we'll learn more soon. - -You can access the fields in a tuple through a *destructuring let*. Here's -an example: - -```rust -let (x, y, z) = (1, 2, 3); - -println!("x is {}", x); -``` - -Remember before when I said the left-hand side of a `let` statement was more -powerful than just assigning a binding? Here we are. We can put a pattern on -the left-hand side of the `let`, and if it matches up to the right-hand side, -we can assign multiple bindings at once. In this case, `let` "destructures," -or "breaks up," the tuple, and assigns the bits to three bindings. - -This pattern is very powerful, and we'll see it repeated more later. - -There are also a few things you can do with a tuple as a whole, without -destructuring. You can assign one tuple into another, if they have the same -contained types and [arity]. Tuples have the same arity when they have the same -length. - -```rust -let mut x = (1, 2); // x: (i32, i32) -let y = (2, 3); // y: (i32, i32) - -x = y; -``` - -You can also check for equality with `==`. Again, this will only compile if the -tuples have the same type. - -```rust -let x = (1, 2, 3); -let y = (2, 2, 4); - -if x == y { - println!("yes"); -} else { - println!("no"); -} -``` - -This will print `no`, because some of the values aren't equal. - -Note that the order of the values is considered when checking for equality, -so the following example will also print `no`. - -```rust -let x = (1, 2, 3); -let y = (2, 1, 3); - -if x == y { - println!("yes"); -} else { - println!("no"); -} -``` - -One other use of tuples is to return multiple values from a function: - -```rust -fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) } - -fn main() { - let (x, y) = next_two(5); - println!("x, y = {}, {}", x, y); -} -``` - -Even though Rust functions can only return one value, a tuple *is* one value, -that happens to be made up of more than one value. You can also see in this -example how you can destructure a pattern returned by a function, as well. - -Tuples are a very simple data structure, and so are not often what you want. -Let's move on to their bigger sibling, structs. - -## Structs - -A struct is another form of a *record type*, just like a tuple. There's a -difference: structs give each element that they contain a name, called a -*field* or a *member*. Check it out: - -```rust -struct Point { - x: i32, - y: i32, -} - -fn main() { - let origin = Point { x: 0, y: 0 }; // origin: Point - - println!("The origin is at ({}, {})", origin.x, origin.y); -} -``` - -There's a lot going on here, so let's break it down. We declare a struct with -the `struct` keyword, and then with a name. By convention, structs begin with a -capital letter and are also camel cased: `PointInSpace`, not `Point_In_Space`. - -We can create an instance of our struct via `let`, as usual, but we use a `key: -value` style syntax to set each field. The order doesn't need to be the same as -in the original declaration. - -Finally, because fields have names, we can access the field through dot -notation: `origin.x`. - -The values in structs are immutable by default, like other bindings in Rust. -Use `mut` to make them mutable: - -```{rust} -struct Point { - x: i32, - y: i32, -} - -fn main() { - let mut point = Point { x: 0, y: 0 }; - - point.x = 5; - - println!("The point is at ({}, {})", point.x, point.y); -} -``` - -This will print `The point is at (5, 0)`. - -## Tuple Structs and Newtypes - -Rust has another data type that's like a hybrid between a tuple and a struct, -called a *tuple struct*. Tuple structs do have a name, but their fields don't: - - -```{rust} -struct Color(i32, i32, i32); -struct Point(i32, i32, i32); -``` - -These two will not be equal, even if they have the same values: - -```{rust} -# struct Color(i32, i32, i32); -# struct Point(i32, i32, i32); -let black = Color(0, 0, 0); -let origin = Point(0, 0, 0); -``` - -It is almost always better to use a struct than a tuple struct. We would write -`Color` and `Point` like this instead: - -```{rust} -struct Color { - red: i32, - blue: i32, - green: i32, -} - -struct Point { - x: i32, - y: i32, - z: i32, -} -``` - -Now, we have actual names, rather than positions. Good names are important, -and with a struct, we have actual names. - -There _is_ one case when a tuple struct is very useful, though, and that's a -tuple struct with only one element. We call this the *newtype* pattern, because -it allows you to create a new type, distinct from that of its contained value -and expressing its own semantic meaning: - -```{rust} -struct Inches(i32); - -let length = Inches(10); - -let Inches(integer_length) = length; -println!("length is {} inches", integer_length); -``` - -As you can see here, you can extract the inner integer type through a -destructuring `let`, as we discussed previously in 'tuples.' In this case, the -`let Inches(integer_length)` assigns `10` to `integer_length`. - -## Enums - -Finally, Rust has a "sum type", an *enum*. Enums are an incredibly useful -feature of Rust, and are used throughout the standard library. An `enum` is -a type which relates a set of alternates to a specific name. For example, below -we define `Character` to be either a `Digit` or something else. These -can be used via their fully scoped names: `Character::Other` (more about `::` -below). - -```rust -enum Character { - Digit(i32), - Other, -} -``` - -Most normal types are allowed as the variant components of an `enum`. Here are -some examples: - -```rust -struct Empty; -struct Color(i32, i32, i32); -struct Length(i32); -struct Status { Health: i32, Mana: i32, Attack: i32, Defense: i32 } -struct HeightDatabase(Vec); -``` - -You see that, depending on its type, an `enum` variant may or may not hold data. -In `Character`, for instance, `Digit` gives a meaningful name for an `i32` -value, where `Other` is only a name. However, the fact that they represent -distinct categories of `Character` is a very useful property. - -As with structures, the variants of an enum by default are not comparable with -equality operators (`==`, `!=`), have no ordering (`<`, `>=`, etc.), and do not -support other binary operations such as `*` and `+`. As such, the following code -is invalid for the example `Character` type: - -```{rust,ignore} -// These assignments both succeed -let ten = Character::Digit(10); -let four = Character::Digit(4); - -// Error: `*` is not implemented for type `Character` -let forty = ten * four; - -// Error: `<=` is not implemented for type `Character` -let four_is_smaller = four <= ten; - -// Error: `==` is not implemented for type `Character` -let four_equals_ten = four == ten; -``` - -This may seem rather limiting, but it's a limitation which we can overcome. -There are two ways: by implementing equality ourselves, or by pattern matching -variants with [`match`][match] expressions, which you'll learn in the next -chapter. We don't know enough about Rust to implement equality yet, but we can -use the `Ordering` enum from the standard library, which does: - -``` -enum Ordering { - Less, - Equal, - Greater, -} -``` - -Because `Ordering` has already been defined for us, we will import it with the -`use` keyword. Here's an example of how it is used: - -```{rust} -use std::cmp::Ordering; - -fn cmp(a: i32, b: i32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} - -fn main() { - let x = 5; - let y = 10; - - let ordering = cmp(x, y); // ordering: Ordering - - if ordering == Ordering::Less { - println!("less"); - } else if ordering == Ordering::Greater { - println!("greater"); - } else if ordering == Ordering::Equal { - println!("equal"); - } -} -``` - -The `::` symbol is used to indicate a namespace. In this case, `Ordering` lives -in the `cmp` submodule of the `std` module. We'll talk more about modules later -in the guide. For now, all you need to know is that you can `use` things from -the standard library if you need them. - -Okay, let's talk about the actual code in the example. `cmp` is a function that -compares two things, and returns an `Ordering`. We return either -`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on -whether the first value is less than, greater than, or equal to the second. Note -that each variant of the `enum` is namespaced under the `enum` itself: it's -`Ordering::Greater`, not `Greater`. - -The `ordering` variable has the type `Ordering`, and so contains one of the -three values. We then do a bunch of `if`/`else` comparisons to check which -one it is. - -This `Ordering::Greater` notation is too long. Let's use another form of `use` -to import the `enum` variants instead. This will avoid full scoping: - -```{rust} -use std::cmp::Ordering::{self, Equal, Less, Greater}; - -fn cmp(a: i32, b: i32) -> Ordering { - if a < b { Less } - else if a > b { Greater } - else { Equal } -} - -fn main() { - let x = 5; - let y = 10; - - let ordering = cmp(x, y); // ordering: Ordering - - if ordering == Less { println!("less"); } - else if ordering == Greater { println!("greater"); } - else if ordering == Equal { println!("equal"); } -} -``` - -Importing variants is convenient and compact, but can also cause name conflicts, -so do this with caution. For this reason, it's normally considered better style -to `use` an enum rather than its variants directly. - -As you can see, `enum`s are quite a powerful tool for data representation, and -are even more useful when they're [generic][generics] across types. Before we -get to generics, though, let's talk about how to use enums with pattern -matching, a tool that will let us deconstruct sum types (the type theory term -for enums) like `Ordering` in a very elegant way that avoids all these messy -and brittle `if`/`else`s. - - -[arity]: ./glossary.html#arity -[match]: ./match.html -[generics]: ./generics.html diff --git a/src/doc/trpl/conclusion.md b/src/doc/trpl/conclusion.md deleted file mode 100644 index 9afddb11314fe..0000000000000 --- a/src/doc/trpl/conclusion.md +++ /dev/null @@ -1,11 +0,0 @@ -% Conclusion - -We covered a lot of ground here. When you've mastered everything in this Guide, -you will have a firm grasp of Rust development. There's a whole lot more -out there, though, we've just covered the surface. There's tons of topics that -you can dig deeper into, e.g. by reading the API documentation of the -[standard library](http://doc.rust-lang.org/std/), by discovering solutions for -common problems on [Rust by Example](http://rustbyexample.com/), or by browsing -crates written by the community on [crates.io](https://crates.io/). - -Happy hacking! diff --git a/src/doc/trpl/concurrency.md b/src/doc/trpl/concurrency.md index f9358f28b0194..e69de29bb2d1d 100644 --- a/src/doc/trpl/concurrency.md +++ b/src/doc/trpl/concurrency.md @@ -1,358 +0,0 @@ -% Concurrency - -Concurrency and parallelism are incredibly important topics in computer -science, and are also a hot topic in industry today. Computers are gaining more -and more cores, yet many programmers aren't prepared to fully utilize them. - -Rust's memory safety features also apply to its concurrency story too. Even -concurrent Rust programs must be memory safe, having no data races. Rust's type -system is up to the task, and gives you powerful ways to reason about -concurrent code at compile time. - -Before we talk about the concurrency features that come with Rust, it's important -to understand something: Rust is low-level enough that all of this is provided -by the standard library, not by the language. This means that if you don't like -some aspect of the way Rust handles concurrency, you can implement an alternative -way of doing things. [mio](https://github.com/carllerche/mio) is a real-world -example of this principle in action. - -## Background: `Send` and `Sync` - -Concurrency is difficult to reason about. In Rust, we have a strong, static -type system to help us reason about our code. As such, Rust gives us two traits -to help us make sense of code that can possibly be concurrent. - -### `Send` - -The first trait we're going to talk about is -[`Send`](../std/marker/trait.Send.html). When a type `T` implements `Send`, it indicates -to the compiler that something of this type is able to have ownership transferred -safely between threads. - -This is important to enforce certain restrictions. For example, if we have a -channel connecting two threads, we would want to be able to send some data -down the channel and to the other thread. Therefore, we'd ensure that `Send` was -implemented for that type. - -In the opposite way, if we were wrapping a library with FFI that isn't -threadsafe, we wouldn't want to implement `Send`, and so the compiler will help -us enforce that it can't leave the current thread. - -### `Sync` - -The second of these traits is called [`Sync`](../std/marker/trait.Sync.html). -When a type `T` implements `Sync`, it indicates to the compiler that something -of this type has no possibility of introducing memory unsafety when used from -multiple threads concurrently. - -For example, sharing immutable data with an atomic reference count is -threadsafe. Rust provides a type like this, `Arc`, and it implements `Sync`, -so it is safe to share between threads. - -These two traits allow you to use the type system to make strong guarantees -about the properties of your code under concurrency. Before we demonstrate -why, we need to learn how to create a concurrent Rust program in the first -place! - -## Threads - -Rust's standard library provides a library for 'threads', which allow you to -run Rust code in parallel. Here's a basic example of using `std::thread`: - -``` -use std::thread; - -fn main() { - thread::scoped(|| { - println!("Hello from a thread!"); - }); -} -``` - -The `thread::scoped()` method accepts a closure, which is executed in a new -thread. It's called `scoped` because this thread returns a join guard: - -``` -use std::thread; - -fn main() { - let guard = thread::scoped(|| { - println!("Hello from a thread!"); - }); - - // guard goes out of scope here -} -``` - -When `guard` goes out of scope, it will block execution until the thread is -finished. If we didn't want this behaviour, we could use `thread::spawn()`: - -``` -use std::thread; - -fn main() { - thread::spawn(|| { - println!("Hello from a thread!"); - }); - - thread::sleep_ms(50); -} -``` - -We need to `sleep` here because when `main()` ends, it kills all of the -running threads. - -[`scoped`](std/thread/struct.Builder.html#method.scoped) has an interesting -type signature: - -```text -fn scoped<'a, T, F>(self, f: F) -> JoinGuard<'a, T> - where T: Send + 'a, - F: FnOnce() -> T, - F: Send + 'a -``` - -Specifically, `F`, the closure that we pass to execute in the new thread. It -has two restrictions: It must be a `FnOnce` from `()` to `T`. Using `FnOnce` -allows the closure to take ownership of any data it mentions from the parent -thread. The other restriction is that `F` must be `Send`. We aren't allowed to -transfer this ownership unless the type thinks that's okay. - -Many languages have the ability to execute threads, but it's wildly unsafe. -There are entire books about how to prevent errors that occur from shared -mutable state. Rust helps out with its type system here as well, by preventing -data races at compile time. Let's talk about how you actually share things -between threads. - -## Safe Shared Mutable State - -Due to Rust's type system, we have a concept that sounds like a lie: "safe -shared mutable state." Many programmers agree that shared mutable state is -very, very bad. - -Someone once said this: - -> Shared mutable state is the root of all evil. Most languages attempt to deal -> with this problem through the 'mutable' part, but Rust deals with it by -> solving the 'shared' part. - -The same [ownership system](ownership.html) that helps prevent using pointers -incorrectly also helps rule out data races, one of the worst kinds of -concurrency bugs. - -As an example, here is a Rust program that would have a data race in many -languages. It will not compile: - -```ignore -use std::thread; - -fn main() { - let mut data = vec![1u32, 2, 3]; - - for i in 0..2 { - thread::spawn(move || { - data[i] += 1; - }); - } - - thread::sleep_ms(50); -} -``` - -This gives us an error: - -```text -8:17 error: capture of moved value: `data` - data[i] += 1; - ^~~~ -``` - -In this case, we know that our code _should_ be safe, but Rust isn't sure. And -it's actually not safe: if we had a reference to `data` in each thread, and the -thread takes ownership of the reference, we have three owners! That's bad. We -can fix this by using the `Arc` type, which is an atomic reference counted -pointer. The 'atomic' part means that it's safe to share across threads. - -`Arc` assumes one more property about its contents to ensure that it is safe -to share across threads: it assumes its contents are `Sync`. But in our -case, we want to be able to mutate the value. We need a type that can ensure -only one person at a time can mutate what's inside. For that, we can use the -`Mutex` type. Here's the second version of our code. It still doesn't work, -but for a different reason: - -```ignore -use std::thread; -use std::sync::Mutex; - -fn main() { - let mut data = Mutex::new(vec![1u32, 2, 3]); - - for i in 0..2 { - let data = data.lock().unwrap(); - thread::spawn(move || { - data[i] += 1; - }); - } - - thread::sleep_ms(50); -} -``` - -Here's the error: - -```text -:9:9: 9:22 error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec>` [E0277] -:11 thread::spawn(move || { - ^~~~~~~~~~~~~ -:9:9: 9:22 note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec>` cannot be sent between threads safely -:11 thread::spawn(move || { - ^~~~~~~~~~~~~ -``` - -You see, [`Mutex`](std/sync/struct.Mutex.html) has a -[`lock`](http://doc.rust-lang.org/nightly/std/sync/struct.Mutex.html#method.lock) -method which has this signature: - -```ignore -fn lock(&self) -> LockResult> -``` - -Because `Send` is not implemented for `MutexGuard`, we can't transfer the -guard across thread boundaries, which gives us our error. - -We can use `Arc` to fix this. Here's the working version: - -``` -use std::sync::{Arc, Mutex}; -use std::thread; - -fn main() { - let data = Arc::new(Mutex::new(vec![1u32, 2, 3])); - - for i in 0..2 { - let data = data.clone(); - thread::spawn(move || { - let mut data = data.lock().unwrap(); - data[i] += 1; - }); - } - - thread::sleep_ms(50); -} -``` - -We now call `clone()` on our `Arc`, which increases the internal count. This -handle is then moved into the new thread. Let's examine the body of the -thread more closely: - -```rust -# use std::sync::{Arc, Mutex}; -# use std::thread; -# fn main() { -# let data = Arc::new(Mutex::new(vec![1u32, 2, 3])); -# for i in 0..2 { -# let data = data.clone(); -thread::spawn(move || { - let mut data = data.lock().unwrap(); - data[i] += 1; -}); -# } -# thread::sleep_ms(50); -# } -``` - -First, we call `lock()`, which acquires the mutex's lock. Because this may fail, -it returns an `Result`, and because this is just an example, we `unwrap()` -it to get a reference to the data. Real code would have more robust error handling -here. We're then free to mutate it, since we have the lock. - -Lastly, while the threads are running, we wait on a short timer. But -this is not ideal: we may have picked a reasonable amount of time to -wait but it's more likely we'll either be waiting longer than -necessary or not long enough, depending on just how much time the -threads actually take to finish computing when the program runs. - -A more precise alternative to the timer would be to use one of the -mechanisms provided by the Rust standard library for synchronizing -threads with each other. Let's talk about one of them: channels. - -## Channels - -Here's a version of our code that uses channels for synchronization, rather -than waiting for a specific time: - -``` -use std::sync::{Arc, Mutex}; -use std::thread; -use std::sync::mpsc; - -fn main() { - let data = Arc::new(Mutex::new(0u32)); - - let (tx, rx) = mpsc::channel(); - - for _ in 0..10 { - let (data, tx) = (data.clone(), tx.clone()); - - thread::spawn(move || { - let mut data = data.lock().unwrap(); - *data += 1; - - tx.send(()); - }); - } - - for _ in 0..10 { - rx.recv(); - } -} -``` - -We use the `mpsc::channel()` method to construct a new channel. We just `send` -a simple `()` down the channel, and then wait for ten of them to come back. - -While this channel is just sending a generic signal, we can send any data that -is `Send` over the channel! - -``` -use std::thread; -use std::sync::mpsc; - -fn main() { - let (tx, rx) = mpsc::channel(); - - for _ in 0..10 { - let tx = tx.clone(); - - thread::spawn(move || { - let answer = 42u32; - - tx.send(answer); - }); - } - - rx.recv().ok().expect("Could not receive answer"); -} -``` - -A `u32` is `Send` because we can make a copy. So we create a thread, ask it to calculate -the answer, and then it `send()`s us the answer over the channel. - - -## Panics - -A `panic!` will crash the currently executing thread. You can use Rust's -threads as a simple isolation mechanism: - -``` -use std::thread; - -let result = thread::spawn(move || { - panic!("oops!"); -}).join(); - -assert!(result.is_err()); -``` - -Our `Thread` gives us a `Result` back, which allows us to check if the thread -has panicked or not. diff --git a/src/doc/trpl/conditional-compilation.md b/src/doc/trpl/conditional-compilation.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/const.md b/src/doc/trpl/const.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/crates-and-modules.md b/src/doc/trpl/crates-and-modules.md index 83e8cc629fd5e..e69de29bb2d1d 100644 --- a/src/doc/trpl/crates-and-modules.md +++ b/src/doc/trpl/crates-and-modules.md @@ -1,533 +0,0 @@ -% Crates and Modules - -When a project starts getting large, it's considered good software -engineering practice to split it up into a bunch of smaller pieces, and then -fit them together. It's also important to have a well-defined interface, so -that some of your functionality is private, and some is public. To facilitate -these kinds of things, Rust has a module system. - -# Basic terminology: Crates and Modules - -Rust has two distinct terms that relate to the module system: *crate* and -*module*. A crate is synonymous with a *library* or *package* in other -languages. Hence "Cargo" as the name of Rust's package management tool: you -ship your crates to others with Cargo. Crates can produce an executable or a -library, depending on the project. - -Each crate has an implicit *root module* that contains the code for that crate. -You can then define a tree of sub-modules under that root module. Modules allow -you to partition your code within the crate itself. - -As an example, let's make a *phrases* crate, which will give us various phrases -in different languages. To keep things simple, we'll stick to "greetings" and -"farewells" as two kinds of phrases, and use English and Japanese (日本語) as -two languages for those phrases to be in. We'll use this module layout: - -```text - +-----------+ - +---| greetings | - | +-----------+ - +---------+ | - +---| english |---+ - | +---------+ | +-----------+ - | +---| farewells | -+---------+ | +-----------+ -| phrases |---+ -+---------+ | +-----------+ - | +---| greetings | - | +----------+ | +-----------+ - +---| japanese |--+ - +----------+ | - | +-----------+ - +---| farewells | - +-----------+ -``` - -In this example, `phrases` is the name of our crate. All of the rest are -modules. You can see that they form a tree, branching out from the crate -*root*, which is the root of the tree: `phrases` itself. - -Now that we have a plan, let's define these modules in code. To start, -generate a new crate with Cargo: - -```bash -$ cargo new phrases -$ cd phrases -``` - -If you remember, this generates a simple project for us: - -```bash -$ tree . -. -├── Cargo.toml -└── src - └── lib.rs - -1 directory, 2 files -``` - -`src/lib.rs` is our crate root, corresponding to the `phrases` in our diagram -above. - -# Defining Modules - -To define each of our modules, we use the `mod` keyword. Let's make our -`src/lib.rs` look like this: - -``` -mod english { - mod greetings { - } - - mod farewells { - } -} - -mod japanese { - mod greetings { - } - - mod farewells { - } -} -``` - -After the `mod` keyword, you give the name of the module. Module names follow -the conventions for other Rust identifiers: `lower_snake_case`. The contents of -each module are within curly braces (`{}`). - -Within a given `mod`, you can declare sub-`mod`s. We can refer to sub-modules -with double-colon (`::`) notation: our four nested modules are -`english::greetings`, `english::farewells`, `japanese::greetings`, and -`japanese::farewells`. Because these sub-modules are namespaced under their -parent module, the names don't conflict: `english::greetings` and -`japanese::greetings` are distinct, even though their names are both -`greetings`. - -Because this crate does not have a `main()` function, and is called `lib.rs`, -Cargo will build this crate as a library: - -```bash -$ cargo build - Compiling phrases v0.0.1 (file:///home/you/projects/phrases) -$ ls target/debug -build deps examples libphrases-a7448e02a0468eaa.rlib native -``` - -`libphrase-hash.rlib` is the compiled crate. Before we see how to use this -crate from another crate, let's break it up into multiple files. - -# Multiple file crates - -If each crate were just one file, these files would get very large. It's often -easier to split up crates into multiple files, and Rust supports this in two -ways. - -Instead of declaring a module like this: - -```{rust,ignore} -mod english { - // contents of our module go here -} -``` - -We can instead declare our module like this: - -```{rust,ignore} -mod english; -``` - -If we do that, Rust will expect to find either a `english.rs` file, or a -`english/mod.rs` file with the contents of our module. - -Note that in these files, you don't need to re-declare the module: that's -already been done with the initial `mod` declaration. - -Using these two techniques, we can break up our crate into two directories and -seven files: - -```bash -$ tree . -. -├── Cargo.lock -├── Cargo.toml -├── src -│   ├── english -│   │   ├── farewells.rs -│   │   ├── greetings.rs -│   │   └── mod.rs -│   ├── japanese -│   │   ├── farewells.rs -│   │   ├── greetings.rs -│   │   └── mod.rs -│   └── lib.rs -└── target - └── debug - ├── build - ├── deps - ├── examples - ├── libphrases-a7448e02a0468eaa.rlib - └── native -``` - -`src/lib.rs` is our crate root, and looks like this: - -```{rust,ignore} -mod english; -mod japanese; -``` - -These two declarations tell Rust to look for either `src/english.rs` and -`src/japanese.rs`, or `src/english/mod.rs` and `src/japanese/mod.rs`, depending -on our preference. In this case, because our modules have sub-modules, we've -chosen the second. Both `src/english/mod.rs` and `src/japanese/mod.rs` look -like this: - -```{rust,ignore} -mod greetings; -mod farewells; -``` - -Again, these declarations tell Rust to look for either -`src/english/greetings.rs` and `src/japanese/greetings.rs` or -`src/english/farewells/mod.rs` and `src/japanese/farewells/mod.rs`. Because -these sub-modules don't have their own sub-modules, we've chosen to make them -`src/english/greetings.rs` and `src/japanese/farewells.rs`. Whew! - -The contents of `src/english/greetings.rs` and `src/japanese/farewells.rs` are -both empty at the moment. Let's add some functions. - -Put this in `src/english/greetings.rs`: - -```rust -fn hello() -> String { - "Hello!".to_string() -} -``` - -Put this in `src/english/farewells.rs`: - -```rust -fn goodbye() -> String { - "Goodbye.".to_string() -} -``` - -Put this in `src/japanese/greetings.rs`: - -```rust -fn hello() -> String { - "こんにちは".to_string() -} -``` - -Of course, you can copy and paste this from this web page, or just type -something else. It's not important that you actually put "konnichiwa" to learn -about the module system. - -Put this in `src/japanese/farewells.rs`: - -```rust -fn goodbye() -> String { - "さようなら".to_string() -} -``` - -(This is "Sayōnara", if you're curious.) - -Now that we have some functionality in our crate, let's try to use it from -another crate. - -# Importing External Crates - -We have a library crate. Let's make an executable crate that imports and uses -our library. - -Make a `src/main.rs` and put this in it (it won't quite compile yet): - -```rust,ignore -extern crate phrases; - -fn main() { - println!("Hello in English: {}", phrases::english::greetings::hello()); - println!("Goodbye in English: {}", phrases::english::farewells::goodbye()); - - println!("Hello in Japanese: {}", phrases::japanese::greetings::hello()); - println!("Goodbye in Japanese: {}", phrases::japanese::farewells::goodbye()); -} -``` - -The `extern crate` declaration tells Rust that we need to compile and link to -the `phrases` crate. We can then use `phrases`' modules in this one. As we -mentioned earlier, you can use double colons to refer to sub-modules and the -functions inside of them. - -Also, Cargo assumes that `src/main.rs` is the crate root of a binary crate, -rather than a library crate. Our package now has two crates: `src/lib.rs` and -`src/main.rs`. This pattern is quite common for executable crates: most -functionality is in a library crate, and the executable crate uses that -library. This way, other programs can also use the library crate, and it's also -a nice separation of concerns. - -This doesn't quite work yet, though. We get four errors that look similar to -this: - -```bash -$ cargo build - Compiling phrases v0.0.1 (file:///home/you/projects/phrases) -src/main.rs:4:38: 4:72 error: function `hello` is private -src/main.rs:4 println!("Hello in English: {}", phrases::english::greetings::hello()); - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -note: in expansion of format_args! -:2:25: 2:58 note: expansion site -:1:1: 2:62 note: in expansion of print! -:3:1: 3:54 note: expansion site -:1:1: 3:58 note: in expansion of println! -phrases/src/main.rs:4:5: 4:76 note: expansion site -``` - -By default, everything is private in Rust. Let's talk about this in some more -depth. - -# Exporting a Public Interface - -Rust allows you to precisely control which aspects of your interface are -public, and so private is the default. To make things public, you use the `pub` -keyword. Let's focus on the `english` module first, so let's reduce our `src/main.rs` -to just this: - -```{rust,ignore} -extern crate phrases; - -fn main() { - println!("Hello in English: {}", phrases::english::greetings::hello()); - println!("Goodbye in English: {}", phrases::english::farewells::goodbye()); -} -``` - -In our `src/lib.rs`, let's add `pub` to the `english` module declaration: - -```{rust,ignore} -pub mod english; -mod japanese; -``` - -And in our `src/english/mod.rs`, let's make both `pub`: - -```{rust,ignore} -pub mod greetings; -pub mod farewells; -``` - -In our `src/english/greetings.rs`, let's add `pub` to our `fn` declaration: - -```{rust,ignore} -pub fn hello() -> String { - "Hello!".to_string() -} -``` - -And also in `src/english/farewells.rs`: - -```{rust,ignore} -pub fn goodbye() -> String { - "Goodbye.".to_string() -} -``` - -Now, our crate compiles, albeit with warnings about not using the `japanese` -functions: - -```bash -$ cargo run - Compiling phrases v0.0.1 (file:///home/you/projects/phrases) -src/japanese/greetings.rs:1:1: 3:2 warning: function is never used: `hello`, #[warn(dead_code)] on by default -src/japanese/greetings.rs:1 fn hello() -> String { -src/japanese/greetings.rs:2 "こんにちは".to_string() -src/japanese/greetings.rs:3 } -src/japanese/farewells.rs:1:1: 3:2 warning: function is never used: `goodbye`, #[warn(dead_code)] on by default -src/japanese/farewells.rs:1 fn goodbye() -> String { -src/japanese/farewells.rs:2 "さようなら".to_string() -src/japanese/farewells.rs:3 } - Running `target/debug/phrases` -Hello in English: Hello! -Goodbye in English: Goodbye. -``` - -Now that our functions are public, we can use them. Great! However, typing out -`phrases::english::greetings::hello()` is very long and repetitive. Rust has -another keyword for importing names into the current scope, so that you can -refer to them with shorter names. Let's talk about `use`. - -# Importing Modules with `use` - -Rust has a `use` keyword, which allows us to import names into our local scope. -Let's change our `src/main.rs` to look like this: - -```{rust,ignore} -extern crate phrases; - -use phrases::english::greetings; -use phrases::english::farewells; - -fn main() { - println!("Hello in English: {}", greetings::hello()); - println!("Goodbye in English: {}", farewells::goodbye()); -} -``` - -The two `use` lines import each module into the local scope, so we can refer to -the functions by a much shorter name. By convention, when importing functions, it's -considered best practice to import the module, rather than the function directly. In -other words, you _can_ do this: - -```{rust,ignore} -extern crate phrases; - -use phrases::english::greetings::hello; -use phrases::english::farewells::goodbye; - -fn main() { - println!("Hello in English: {}", hello()); - println!("Goodbye in English: {}", goodbye()); -} -``` - -But it is not idiomatic. This is significantly more likely to introduce a -naming conflict. In our short program, it's not a big deal, but as it grows, it -becomes a problem. If we have conflicting names, Rust will give a compilation -error. For example, if we made the `japanese` functions public, and tried to do -this: - -```{rust,ignore} -extern crate phrases; - -use phrases::english::greetings::hello; -use phrases::japanese::greetings::hello; - -fn main() { - println!("Hello in English: {}", hello()); - println!("Hello in Japanese: {}", hello()); -} -``` - -Rust will give us a compile-time error: - -```text - Compiling phrases v0.0.1 (file:///home/you/projects/phrases) -src/main.rs:4:5: 4:40 error: a value named `hello` has already been imported in this module [E0252] -src/main.rs:4 use phrases::japanese::greetings::hello; - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -error: aborting due to previous error -Could not compile `phrases`. -``` - -If we're importing multiple names from the same module, we don't have to type it out -twice. Instead of this: - -```{rust,ignore} -use phrases::english::greetings; -use phrases::english::farewells; -``` - -We can use this shortcut: - -```{rust,ignore} -use phrases::english::{greetings, farewells}; -``` - -## Re-exporting with `pub use` - -You don't just use `use` to shorten identifiers. You can also use it inside of your crate -to re-export a function inside another module. This allows you to present an external -interface that may not directly map to your internal code organization. - -Let's look at an example. Modify your `src/main.rs` to read like this: - -```{rust,ignore} -extern crate phrases; - -use phrases::english::{greetings,farewells}; -use phrases::japanese; - -fn main() { - println!("Hello in English: {}", greetings::hello()); - println!("Goodbye in English: {}", farewells::goodbye()); - - println!("Hello in Japanese: {}", japanese::hello()); - println!("Goodbye in Japanese: {}", japanese::goodbye()); -} -``` - -Then, modify your `src/lib.rs` to make the `japanese` mod public: - -```{rust,ignore} -pub mod english; -pub mod japanese; -``` - -Next, make the two functions public, first in `src/japanese/greetings.rs`: - -```{rust,ignore} -pub fn hello() -> String { - "こんにちは".to_string() -} -``` - -And then in `src/japanese/farewells.rs`: - -```{rust,ignore} -pub fn goodbye() -> String { - "さようなら".to_string() -} -``` - -Finally, modify your `src/japanese/mod.rs` to read like this: - -```{rust,ignore} -pub use self::greetings::hello; -pub use self::farewells::goodbye; - -mod greetings; -mod farewells; -``` - -The `pub use` declaration brings the function into scope at this part of our -module hierarchy. Because we've `pub use`d this inside of our `japanese` -module, we now have a `phrases::japanese::hello()` function and a -`phrases::japanese::goodbye()` function, even though the code for them lives in -`phrases::japanese::greetings::hello()` and -`phrases::japanese::farewells::goodbye()`. Our internal organization doesn't -define our external interface. - -Here we have a `pub use` for each function we want to bring into the -`japanese` scope. We could alternatively use the wildcard syntax to include -everything from `greetings` into the current scope: `pub use self::greetings::*`. - -What about the `self`? Well, by default, `use` declarations are absolute paths, -starting from your crate root. `self` makes that path relative to your current -place in the hierarchy instead. There's one more special form of `use`: you can -`use super::` to reach one level up the tree from your current location. Some -people like to think of `self` as `.` and `super` as `..`, from many shells' -display for the current directory and the parent directory. - -Outside of `use`, paths are relative: `foo::bar()` refers to a function inside -of `foo` relative to where we are. If that's prefixed with `::`, as in -`::foo::bar()`, it refers to a different `foo`, an absolute path from your -crate root. - -Also, note that we `pub use`d before we declared our `mod`s. Rust requires that -`use` declarations go first. - -This will build and run: - -```bash -$ cargo run - Compiling phrases v0.0.1 (file:///home/you/projects/phrases) - Running `target/debug/phrases` -Hello in English: Hello! -Goodbye in English: Goodbye. -Hello in Japanese: こんにちは -Goodbye in Japanese: さようなら -``` diff --git a/src/doc/trpl/debug-and-display.md b/src/doc/trpl/debug-and-display.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/deref-coercions.md b/src/doc/trpl/deref-coercions.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/documentation.md b/src/doc/trpl/documentation.md index 06071a8f15fa4..e69de29bb2d1d 100644 --- a/src/doc/trpl/documentation.md +++ b/src/doc/trpl/documentation.md @@ -1,562 +0,0 @@ -% Documentation - -Documentation is an important part of any software project, and it's -first-class in Rust. Let's talk about the tooling Rust gives you to -document your project. - -## About `rustdoc` - -The Rust distribution includes a tool, `rustdoc`, that generates documentation. -`rustdoc` is also used by Cargo through `cargo doc`. - -Documentation can be generated in two ways: from source code, and from -standalone Markdown files. - -## Documenting source code - -The primary way of documenting a Rust project is through annotating the source -code. You can use documentation comments for this purpose: - -```rust,ignore -/// Constructs a new `Rc`. -/// -/// # Examples -/// -/// ``` -/// use std::rc::Rc; -/// -/// let five = Rc::new(5); -/// ``` -pub fn new(value: T) -> Rc { - // implementation goes here -} -``` - -This code generates documentation that looks [like this][rc-new]. I've left the -implementation out, with a regular comment in its place. That's the first thing -to notice about this annotation: it uses `///`, instead of `//`. The triple slash -indicates a documentation comment. - -Documentation comments are written in Markdown. - -Rust keeps track of these comments, and uses them when generating -documentation. This is important when documenting things like enums: - -``` -/// The `Option` type. See [the module level documentation](../) for more. -enum Option { - /// No value - None, - /// Some value `T` - Some(T), -} -``` - -The above works, but this does not: - -```rust,ignore -/// The `Option` type. See [the module level documentation](../) for more. -enum Option { - None, /// No value - Some(T), /// Some value `T` -} -``` - -You'll get an error: - -```text -hello.rs:4:1: 4:2 error: expected ident, found `}` -hello.rs:4 } - ^ -``` - -This [unfortunate error](https://github.com/rust-lang/rust/issues/22547) is -correct: documentation comments apply to the thing after them, and there's no -thing after that last comment. - -[rc-new]: http://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new - -### Writing documentation comments - -Anyway, let's cover each part of this comment in detail: - -``` -/// Constructs a new `Rc`. -# fn foo() {} -``` - -The first line of a documentation comment should be a short summary of its -functionality. One sentence. Just the basics. High level. - -``` -/// -/// Other details about constructing `Rc`s, maybe describing complicated -/// semantics, maybe additional options, all kinds of stuff. -/// -# fn foo() {} -``` - -Our original example had just a summary line, but if we had more things to say, -we could have added more explanation in a new paragraph. - -#### Special sections - -``` -/// # Examples -# fn foo() {} -``` - -Next, are special sections. These are indicated with a header, `#`. There -are three kinds of headers that are commonly used. They aren't special syntax, -just convention, for now. - -``` -/// # Panics -# fn foo() {} -``` - -Unrecoverable misuses of a function (i.e. programming errors) in Rust are -usually indicated by panics, which kill the whole current thread at the very -least. If your function has a non-trivial contract like this, that is -detected/enforced by panics, documenting it is very important. - -``` -/// # Failures -# fn foo() {} -``` - -If your function or method returns a `Result`, then describing the -conditions under which it returns `Err(E)` is a nice thing to do. This is -slightly less important than `Panics`, because failure is encoded into the type -system, but it's still a good thing to do. - -``` -/// # Safety -# fn foo() {} -``` - -If your function is `unsafe`, you should explain which invariants the caller is -responsible for upholding. - -``` -/// # Examples -/// -/// ``` -/// use std::rc::Rc; -/// -/// let five = Rc::new(5); -/// ``` -# fn foo() {} -``` - -Third, `Examples`. Include one or more examples of using your function or -method, and your users will love you for it. These examples go inside of -code block annotations, which we'll talk about in a moment, and can have -more than one section: - -``` -/// # Examples -/// -/// Simple `&str` patterns: -/// -/// ``` -/// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect(); -/// assert_eq!(v, vec!["Mary", "had", "a", "little", "lamb"]); -/// ``` -/// -/// More complex patterns with a lambda: -/// -/// ``` -/// let v: Vec<&str> = "abc1def2ghi".split(|c: char| c.is_numeric()).collect(); -/// assert_eq!(v, vec!["abc", "def", "ghi"]); -/// ``` -# fn foo() {} -``` - -Let's discuss the details of these code blocks. - -#### Code block annotations - -To write some Rust code in a comment, use the triple graves: - -``` -/// ``` -/// println!("Hello, world"); -/// ``` -# fn foo() {} -``` - -If you want something that's not Rust code, you can add an annotation: - -``` -/// ```c -/// printf("Hello, world\n"); -/// ``` -# fn foo() {} -``` - -This will highlight according to whatever language you're showing off. -If you're just showing plain text, choose `text`. - -It's important to choose the correct annotation here, because `rustdoc` uses it -in an interesting way: It can be used to actually test your examples, so that -they don't get out of date. If you have some C code but `rustdoc` thinks it's -Rust because you left off the annotation, `rustdoc` will complain when trying to -generate the documentation. - -## Documentation as tests - -Let's discuss our sample example documentation: - -``` -/// ``` -/// println!("Hello, world"); -/// ``` -# fn foo() {} -``` - -You'll notice that you don't need a `fn main()` or anything here. `rustdoc` will -automatically add a main() wrapper around your code, and in the right place. -For example: - -``` -/// ``` -/// use std::rc::Rc; -/// -/// let five = Rc::new(5); -/// ``` -# fn foo() {} -``` - -This will end up testing: - -``` -fn main() { - use std::rc::Rc; - let five = Rc::new(5); -} -``` - -Here's the full algorithm rustdoc uses to postprocess examples: - -1. Any leading `#![foo]` attributes are left intact as crate attributes. -2. Some common `allow` attributes are inserted, including - `unused_variables`, `unused_assignments`, `unused_mut`, - `unused_attributes`, and `dead_code`. Small examples often trigger - these lints. -3. If the example does not contain `extern crate`, then `extern crate - ;` is inserted. -2. Finally, if the example does not contain `fn main`, the remainder of the - text is wrapped in `fn main() { your_code }` - -Sometimes, this isn't enough, though. For example, all of these code samples -with `///` we've been talking about? The raw text: - -```text -/// Some documentation. -# fn foo() {} -``` - -looks different than the output: - -``` -/// Some documentation. -# fn foo() {} -``` - -Yes, that's right: you can add lines that start with `# `, and they will -be hidden from the output, but will be used when compiling your code. You -can use this to your advantage. In this case, documentation comments need -to apply to some kind of function, so if I want to show you just a -documentation comment, I need to add a little function definition below -it. At the same time, it's just there to satisfy the compiler, so hiding -it makes the example more clear. You can use this technique to explain -longer examples in detail, while still preserving the testability of your -documentation. For example, this code: - -``` -let x = 5; -let y = 6; -println!("{}", x + y); -``` - -Here's an explanation, rendered: - -First, we set `x` to five: - -``` -let x = 5; -# let y = 6; -# println!("{}", x + y); -``` - -Next, we set `y` to six: - -``` -# let x = 5; -let y = 6; -# println!("{}", x + y); -``` - -Finally, we print the sum of `x` and `y`: - -``` -# let x = 5; -# let y = 6; -println!("{}", x + y); -``` - -Here's the same explanation, in raw text: - -> First, we set `x` to five: -> -> ```text -> let x = 5; -> # let y = 6; -> # println!("{}", x + y); -> ``` -> -> Next, we set `y` to six: -> -> ```text -> # let x = 5; -> let y = 6; -> # println!("{}", x + y); -> ``` -> -> Finally, we print the sum of `x` and `y`: -> -> ```text -> # let x = 5; -> # let y = 6; -> println!("{}", x + y); -> ``` - -By repeating all parts of the example, you can ensure that your example still -compiles, while only showing the parts that are relevant to that part of your -explanation. - -### Documenting macros - -Here’s an example of documenting a macro: - -``` -/// Panic with a given message unless an expression evaluates to true. -/// -/// # Examples -/// -/// ``` -/// # #[macro_use] extern crate foo; -/// # fn main() { -/// panic_unless!(1 + 1 == 2, “Math is broken.”); -/// # } -/// ``` -/// -/// ```should_panic -/// # #[macro_use] extern crate foo; -/// # fn main() { -/// panic_unless!(true == false, “I’m broken.”); -/// # } -/// ``` -#[macro_export] -macro_rules! panic_unless { - ($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } }); -} -# fn main() {} -``` - -You’ll note three things: we need to add our own `extern crate` line, so that -we can add the `#[macro_use]` attribute. Second, we’ll need to add our own -`main()` as well. Finally, a judicious use of `#` to comment out those two -things, so they don’t show up in the output. - -### Running documentation tests - -To run the tests, either - -```bash -$ rustdoc --test path/to/my/crate/root.rs -# or -$ cargo test -``` - -That's right, `cargo test` tests embedded documentation too. - -There are a few more annotations that are useful to help `rustdoc` do the right -thing when testing your code: - -``` -/// ```ignore -/// fn foo() { -/// ``` -# fn foo() {} -``` - -The `ignore` directive tells Rust to ignore your code. This is almost never -what you want, as it's the most generic. Instead, consider annotating it -with `text` if it's not code, or using `#`s to get a working example that -only shows the part you care about. - -``` -/// ```should_panic -/// assert!(false); -/// ``` -# fn foo() {} -``` - -`should_panic` tells `rustdoc` that the code should compile correctly, but -not actually pass as a test. - -``` -/// ```no_run -/// loop { -/// println!("Hello, world"); -/// } -/// ``` -# fn foo() {} -``` - -The `no_run` attribute will compile your code, but not run it. This is -important for examples such as "Here's how to start up a network service," -which you would want to make sure compile, but might run in an infinite loop! - -### Documenting modules - -Rust has another kind of doc comment, `//!`. This comment doesn't document the next item, but the enclosing item. In other words: - -``` -mod foo { - //! This is documentation for the `foo` module. - //! - //! # Examples - - // ... -} -``` - -This is where you'll see `//!` used most often: for module documentation. If -you have a module in `foo.rs`, you'll often open its code and see this: - -``` -//! A module for using `foo`s. -//! -//! The `foo` module contains a lot of useful functionality blah blah blah -``` - -### Documentation comment style - -Check out [RFC 505][rfc505] for full conventions around the style and format of -documentation. - -[rfc505]: https://github.com/rust-lang/rfcs/blob/master/text/0505-api-comment-conventions.md - -## Other documentation - -All of this behavior works in non-Rust source files too. Because comments -are written in Markdown, they're often `.md` files. - -When you write documentation in Markdown files, you don't need to prefix -the documentation with comments. For example: - -``` -/// # Examples -/// -/// ``` -/// use std::rc::Rc; -/// -/// let five = Rc::new(5); -/// ``` -# fn foo() {} -``` - -is just - -~~~markdown -# Examples - -``` -use std::rc::Rc; - -let five = Rc::new(5); -``` -~~~ - -when it's in a Markdown file. There is one wrinkle though: Markdown files need -to have a title like this: - -```markdown -% The title - -This is the example documentation. -``` - -This `%` line needs to be the very first line of the file. - -## `doc` attributes - -At a deeper level, documentation comments are sugar for documentation attributes: - -``` -/// this -# fn foo() {} - -#[doc="this"] -# fn bar() {} -``` - -are the same, as are these: - -``` -//! this - -#![doc="/// this"] -``` - -You won't often see this attribute used for writing documentation, but it -can be useful when changing some options, or when writing a macro. - -### Re-exports - -`rustdoc` will show the documentation for a public re-export in both places: - -```ignore -extern crate foo; - -pub use foo::bar; -``` - -This will create documentation for bar both inside the documentation for the -crate `foo`, as well as the documentation for your crate. It will use the same -documentation in both places. - -This behavior can be suppressed with `no_inline`: - -```ignore -extern crate foo; - -#[doc(no_inline)] -pub use foo::bar; -``` - -### Controlling HTML - -You can control a few aspects of the HTML that `rustdoc` generates through the -`#![doc]` version of the attribute: - -``` -#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "http://www.rust-lang.org/favicon.ico", - html_root_url = "http://doc.rust-lang.org/")]; -``` - -This sets a few different options, with a logo, favicon, and a root URL. - -## Generation options - -`rustdoc` also contains a few other options on the command line, for further customiziation: - -- `--html-in-header FILE`: includes the contents of FILE at the end of the - `...` section. -- `--html-before-content FILE`: includes the contents of FILE directly after - ``, before the rendered content (including the search bar). -- `--html-after-content FILE`: includes the contents of FILE after all the rendered content. diff --git a/src/doc/trpl/drop.md b/src/doc/trpl/drop.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/effective-rust.md b/src/doc/trpl/effective-rust.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/enums.md b/src/doc/trpl/enums.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index b9e7bd78c5b2f..e69de29bb2d1d 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -1,301 +0,0 @@ -% Error Handling - -> The best-laid plans of mice and men -> Often go awry -> -> "Tae a Moose", Robert Burns - -Sometimes, things just go wrong. It's important to have a plan for when the -inevitable happens. Rust has rich support for handling errors that may (let's -be honest: will) occur in your programs. - -There are two main kinds of errors that can occur in your programs: failures, -and panics. Let's talk about the difference between the two, and then discuss -how to handle each. Then, we'll discuss upgrading failures to panics. - -# Failure vs. Panic - -Rust uses two terms to differentiate between two forms of error: failure, and -panic. A *failure* is an error that can be recovered from in some way. A -*panic* is an error that cannot be recovered from. - -What do we mean by "recover"? Well, in most cases, the possibility of an error -is expected. For example, consider the `from_str` function: - -```{rust,ignore} -from_str("5"); -``` - -This function takes a string argument and converts it into another type. But -because it's a string, you can't be sure that the conversion actually works. -For example, what should this convert to? - -```{rust,ignore} -from_str("hello5world"); -``` - -This won't work. So we know that this function will only work properly for some -inputs. It's expected behavior. We call this kind of error a *failure*. - -On the other hand, sometimes, there are errors that are unexpected, or which -we cannot recover from. A classic example is an `assert!`: - -```{rust,ignore} -assert!(x == 5); -``` - -We use `assert!` to declare that something is true. If it's not true, something -is very wrong. Wrong enough that we can't continue with things in the current -state. Another example is using the `unreachable!()` macro: - -```{rust,ignore} -enum Event { - NewRelease, -} - -fn probability(_: &Event) -> f64 { - // real implementation would be more complex, of course - 0.95 -} - -fn descriptive_probability(event: Event) -> &'static str { - match probability(&event) { - 1.00 => "certain", - 0.00 => "impossible", - 0.00 ... 0.25 => "very unlikely", - 0.25 ... 0.50 => "unlikely", - 0.50 ... 0.75 => "likely", - 0.75 ... 1.00 => "very likely", - } -} - -fn main() { - std::io::println(descriptive_probability(NewRelease)); -} -``` - -This will give us an error: - -```text -error: non-exhaustive patterns: `_` not covered [E0004] -``` - -While we know that we've covered all possible cases, Rust can't tell. It -doesn't know that probability is between 0.0 and 1.0. So we add another case: - -```rust -use Event::NewRelease; - -enum Event { - NewRelease, -} - -fn probability(_: &Event) -> f64 { - // real implementation would be more complex, of course - 0.95 -} - -fn descriptive_probability(event: Event) -> &'static str { - match probability(&event) { - 1.00 => "certain", - 0.00 => "impossible", - 0.00 ... 0.25 => "very unlikely", - 0.25 ... 0.50 => "unlikely", - 0.50 ... 0.75 => "likely", - 0.75 ... 1.00 => "very likely", - _ => unreachable!() - } -} - -fn main() { - println!("{}", descriptive_probability(NewRelease)); -} -``` - -We shouldn't ever hit the `_` case, so we use the `unreachable!()` macro to -indicate this. `unreachable!()` gives a different kind of error than `Result`. -Rust calls these sorts of errors *panics*. - -# Handling errors with `Option` and `Result` - -The simplest way to indicate that a function may fail is to use the `Option` -type. Remember our `from_str()` example? Here's its type signature: - -```{rust,ignore} -pub fn from_str(s: &str) -> Option -``` - -`from_str()` returns an `Option`. If the conversion succeeds, it will return -`Some(value)`, and if it fails, it will return `None`. - -This is appropriate for the simplest of cases, but doesn't give us a lot of -information in the failure case. What if we wanted to know _why_ the conversion -failed? For this, we can use the `Result` type. It looks like this: - -```rust -enum Result { - Ok(T), - Err(E) -} -``` - -This enum is provided by Rust itself, so you don't need to define it to use it -in your code. The `Ok(T)` variant represents a success, and the `Err(E)` variant -represents a failure. Returning a `Result` instead of an `Option` is recommended -for all but the most trivial of situations. - -Here's an example of using `Result`: - -```rust -#[derive(Debug)] -enum Version { Version1, Version2 } - -#[derive(Debug)] -enum ParseError { InvalidHeaderLength, InvalidVersion } - -fn parse_version(header: &[u8]) -> Result { - if header.len() < 1 { - return Err(ParseError::InvalidHeaderLength); - } - match header[0] { - 1 => Ok(Version::Version1), - 2 => Ok(Version::Version2), - _ => Err(ParseError::InvalidVersion) - } -} - -let version = parse_version(&[1, 2, 3, 4]); -match version { - Ok(v) => { - println!("working with version: {:?}", v); - } - Err(e) => { - println!("error parsing header: {:?}", e); - } -} -``` - -This function makes use of an enum, `ParseError`, to enumerate the various -errors that can occur. - -# Non-recoverable errors with `panic!` - -In the case of an error that is unexpected and not recoverable, the `panic!` -macro will induce a panic. This will crash the current thread, and give an error: - -```{rust,ignore} -panic!("boom"); -``` - -gives - -```text -thread '
' panicked at 'boom', hello.rs:2 -``` - -when you run it. - -Because these kinds of situations are relatively rare, use panics sparingly. - -# Upgrading failures to panics - -In certain circumstances, even though a function may fail, we may want to treat -it as a panic instead. For example, `io::stdin().read_line(&mut buffer)` returns -an `Result`, when there is an error reading the line. This allows us to -handle and possibly recover from error. - -If we don't want to handle this error, and would rather just abort the program, -we can use the `unwrap()` method: - -```{rust,ignore} -io::stdin().read_line(&mut buffer).unwrap(); -``` - -`unwrap()` will `panic!` if the `Option` is `None`. This basically says "Give -me the value, and if something goes wrong, just crash." This is less reliable -than matching the error and attempting to recover, but is also significantly -shorter. Sometimes, just crashing is appropriate. - -There's another way of doing this that's a bit nicer than `unwrap()`: - -```{rust,ignore} -let mut buffer = String::new(); -let input = io::stdin().read_line(&mut buffer) - .ok() - .expect("Failed to read line"); -``` - -`ok()` converts the `Result` into an `Option`, and `expect()` does the same -thing as `unwrap()`, but takes a message. This message is passed along to the -underlying `panic!`, providing a better error message if the code errors. - -# Using `try!` - -When writing code that calls many functions that return the `Result` type, the -error handling can be tedious. The `try!` macro hides some of the boilerplate -of propagating errors up the call stack. - -It replaces this: - -```rust -use std::fs::File; -use std::io; -use std::io::prelude::*; - -struct Info { - name: String, - age: i32, - rating: i32, -} - -fn write_info(info: &Info) -> io::Result<()> { - let mut file = File::open("my_best_friends.txt").unwrap(); - - if let Err(e) = writeln!(&mut file, "name: {}", info.name) { - return Err(e) - } - if let Err(e) = writeln!(&mut file, "age: {}", info.age) { - return Err(e) - } - if let Err(e) = writeln!(&mut file, "rating: {}", info.rating) { - return Err(e) - } - - return Ok(()); -} -``` - -With this: - -```rust -use std::fs::File; -use std::io; -use std::io::prelude::*; - -struct Info { - name: String, - age: i32, - rating: i32, -} - -fn write_info(info: &Info) -> io::Result<()> { - let mut file = try!(File::open("my_best_friends.txt")); - - try!(writeln!(&mut file, "name: {}", info.name)); - try!(writeln!(&mut file, "age: {}", info.age)); - try!(writeln!(&mut file, "rating: {}", info.rating)); - - return Ok(()); -} -``` - -Wrapping an expression in `try!` will result in the unwrapped success (`Ok`) -value, unless the result is `Err`, in which case `Err` is returned early from -the enclosing function. - -It's worth noting that you can only use `try!` from a function that returns a -`Result`, which means that you cannot use `try!` inside of `main()`, because -`main()` doesn't return anything. - -`try!` makes use of [`FromError`](../std/error/#the-fromerror-trait) to determine -what to return in the error case. diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index 23f6e17b860b2..e69de29bb2d1d 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -1,530 +0,0 @@ -% Foreign Function Interface - -# Introduction - -This guide will use the [snappy](https://github.com/google/snappy) -compression/decompression library as an introduction to writing bindings for -foreign code. Rust is currently unable to call directly into a C++ library, but -snappy includes a C interface (documented in -[`snappy-c.h`](https://github.com/google/snappy/blob/master/snappy-c.h)). - -The following is a minimal example of calling a foreign function which will -compile if snappy is installed: - -```no_run -# #![feature(libc)] -extern crate libc; -use libc::size_t; - -#[link(name = "snappy")] -extern { - fn snappy_max_compressed_length(source_length: size_t) -> size_t; -} - -fn main() { - let x = unsafe { snappy_max_compressed_length(100) }; - println!("max compressed length of a 100 byte buffer: {}", x); -} -``` - -The `extern` block is a list of function signatures in a foreign library, in -this case with the platform's C ABI. The `#[link(...)]` attribute is used to -instruct the linker to link against the snappy library so the symbols are -resolved. - -Foreign functions are assumed to be unsafe so calls to them need to be wrapped -with `unsafe {}` as a promise to the compiler that everything contained within -truly is safe. C libraries often expose interfaces that aren't thread-safe, and -almost any function that takes a pointer argument isn't valid for all possible -inputs since the pointer could be dangling, and raw pointers fall outside of -Rust's safe memory model. - -When declaring the argument types to a foreign function, the Rust compiler can -not check if the declaration is correct, so specifying it correctly is part of -keeping the binding correct at runtime. - -The `extern` block can be extended to cover the entire snappy API: - -```no_run -# #![feature(libc)] -extern crate libc; -use libc::{c_int, size_t}; - -#[link(name = "snappy")] -extern { - fn snappy_compress(input: *const u8, - input_length: size_t, - compressed: *mut u8, - compressed_length: *mut size_t) -> c_int; - fn snappy_uncompress(compressed: *const u8, - compressed_length: size_t, - uncompressed: *mut u8, - uncompressed_length: *mut size_t) -> c_int; - fn snappy_max_compressed_length(source_length: size_t) -> size_t; - fn snappy_uncompressed_length(compressed: *const u8, - compressed_length: size_t, - result: *mut size_t) -> c_int; - fn snappy_validate_compressed_buffer(compressed: *const u8, - compressed_length: size_t) -> c_int; -} -# fn main() {} -``` - -# Creating a safe interface - -The raw C API needs to be wrapped to provide memory safety and make use of higher-level concepts -like vectors. A library can choose to expose only the safe, high-level interface and hide the unsafe -internal details. - -Wrapping the functions which expect buffers involves using the `slice::raw` module to manipulate Rust -vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous block of memory. The -length is number of elements currently contained, and the capacity is the total size in elements of -the allocated memory. The length is less than or equal to the capacity. - -``` -# #![feature(libc)] -# extern crate libc; -# use libc::{c_int, size_t}; -# unsafe fn snappy_validate_compressed_buffer(_: *const u8, _: size_t) -> c_int { 0 } -# fn main() {} -pub fn validate_compressed_buffer(src: &[u8]) -> bool { - unsafe { - snappy_validate_compressed_buffer(src.as_ptr(), src.len() as size_t) == 0 - } -} -``` - -The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, but it makes the -guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function -signature. - -The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be -allocated to hold the output too. - -The `snappy_max_compressed_length` function can be used to allocate a vector with the maximum -required capacity to hold the compressed output. The vector can then be passed to the -`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve -the true length after compression for setting the length. - -``` -# #![feature(libc)] -# extern crate libc; -# use libc::{size_t, c_int}; -# unsafe fn snappy_compress(a: *const u8, b: size_t, c: *mut u8, -# d: *mut size_t) -> c_int { 0 } -# unsafe fn snappy_max_compressed_length(a: size_t) -> size_t { a } -# fn main() {} -pub fn compress(src: &[u8]) -> Vec { - unsafe { - let srclen = src.len() as size_t; - let psrc = src.as_ptr(); - - let mut dstlen = snappy_max_compressed_length(srclen); - let mut dst = Vec::with_capacity(dstlen as usize); - let pdst = dst.as_mut_ptr(); - - snappy_compress(psrc, srclen, pdst, &mut dstlen); - dst.set_len(dstlen as usize); - dst - } -} -``` - -Decompression is similar, because snappy stores the uncompressed size as part of the compression -format and `snappy_uncompressed_length` will retrieve the exact buffer size required. - -``` -# #![feature(libc)] -# extern crate libc; -# use libc::{size_t, c_int}; -# unsafe fn snappy_uncompress(compressed: *const u8, -# compressed_length: size_t, -# uncompressed: *mut u8, -# uncompressed_length: *mut size_t) -> c_int { 0 } -# unsafe fn snappy_uncompressed_length(compressed: *const u8, -# compressed_length: size_t, -# result: *mut size_t) -> c_int { 0 } -# fn main() {} -pub fn uncompress(src: &[u8]) -> Option> { - unsafe { - let srclen = src.len() as size_t; - let psrc = src.as_ptr(); - - let mut dstlen: size_t = 0; - snappy_uncompressed_length(psrc, srclen, &mut dstlen); - - let mut dst = Vec::with_capacity(dstlen as usize); - let pdst = dst.as_mut_ptr(); - - if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 { - dst.set_len(dstlen as usize); - Some(dst) - } else { - None // SNAPPY_INVALID_INPUT - } - } -} -``` - -For reference, the examples used here are also available as an [library on -GitHub](https://github.com/thestinger/rust-snappy). - -# Destructors - -Foreign libraries often hand off ownership of resources to the calling code. -When this occurs, we must use Rust's destructors to provide safety and guarantee -the release of these resources (especially in the case of panic). - -For more about destructors, see the [Drop trait](../std/ops/trait.Drop.html). - -# Callbacks from C code to Rust functions - -Some external libraries require the usage of callbacks to report back their -current state or intermediate data to the caller. -It is possible to pass functions defined in Rust to an external library. -The requirement for this is that the callback function is marked as `extern` -with the correct calling convention to make it callable from C code. - -The callback function can then be sent through a registration call -to the C library and afterwards be invoked from there. - -A basic example is: - -Rust code: - -```no_run -extern fn callback(a: i32) { - println!("I'm called from C with value {0}", a); -} - -#[link(name = "extlib")] -extern { - fn register_callback(cb: extern fn(i32)) -> i32; - fn trigger_callback(); -} - -fn main() { - unsafe { - register_callback(callback); - trigger_callback(); // Triggers the callback - } -} -``` - -C code: - -```c -typedef void (*rust_callback)(int32_t); -rust_callback cb; - -int32_t register_callback(rust_callback callback) { - cb = callback; - return 1; -} - -void trigger_callback() { - cb(7); // Will call callback(7) in Rust -} -``` - -In this example Rust's `main()` will call `trigger_callback()` in C, -which would, in turn, call back to `callback()` in Rust. - - -## Targeting callbacks to Rust objects - -The former example showed how a global function can be called from C code. -However it is often desired that the callback is targeted to a special -Rust object. This could be the object that represents the wrapper for the -respective C object. - -This can be achieved by passing an unsafe pointer to the object down to the -C library. The C library can then include the pointer to the Rust object in -the notification. This will allow the callback to unsafely access the -referenced Rust object. - -Rust code: - -```no_run -#[repr(C)] -struct RustObject { - a: i32, - // other members -} - -extern "C" fn callback(target: *mut RustObject, a: i32) { - println!("I'm called from C with value {0}", a); - unsafe { - // Update the value in RustObject with the value received from the callback - (*target).a = a; - } -} - -#[link(name = "extlib")] -extern { - fn register_callback(target: *mut RustObject, - cb: extern fn(*mut RustObject, i32)) -> i32; - fn trigger_callback(); -} - -fn main() { - // Create the object that will be referenced in the callback - let mut rust_object = Box::new(RustObject { a: 5 }); - - unsafe { - register_callback(&mut *rust_object, callback); - trigger_callback(); - } -} -``` - -C code: - -```c -typedef void (*rust_callback)(void*, int32_t); -void* cb_target; -rust_callback cb; - -int32_t register_callback(void* callback_target, rust_callback callback) { - cb_target = callback_target; - cb = callback; - return 1; -} - -void trigger_callback() { - cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust -} -``` - -## Asynchronous callbacks - -In the previously given examples the callbacks are invoked as a direct reaction -to a function call to the external C library. -The control over the current thread is switched from Rust to C to Rust for the -execution of the callback, but in the end the callback is executed on the -same thread that called the function which triggered the callback. - -Things get more complicated when the external library spawns its own threads -and invokes callbacks from there. -In these cases access to Rust data structures inside the callbacks is -especially unsafe and proper synchronization mechanisms must be used. -Besides classical synchronization mechanisms like mutexes, one possibility in -Rust is to use channels (in `std::comm`) to forward data from the C thread -that invoked the callback into a Rust thread. - -If an asynchronous callback targets a special object in the Rust address space -it is also absolutely necessary that no more callbacks are performed by the -C library after the respective Rust object gets destroyed. -This can be achieved by unregistering the callback in the object's -destructor and designing the library in a way that guarantees that no -callback will be performed after deregistration. - -# Linking - -The `link` attribute on `extern` blocks provides the basic building block for -instructing rustc how it will link to native libraries. There are two accepted -forms of the link attribute today: - -* `#[link(name = "foo")]` -* `#[link(name = "foo", kind = "bar")]` - -In both of these cases, `foo` is the name of the native library that we're -linking to, and in the second case `bar` is the type of native library that the -compiler is linking to. There are currently three known types of native -libraries: - -* Dynamic - `#[link(name = "readline")]` -* Static - `#[link(name = "my_build_dependency", kind = "static")]` -* Frameworks - `#[link(name = "CoreFoundation", kind = "framework")]` - -Note that frameworks are only available on OSX targets. - -The different `kind` values are meant to differentiate how the native library -participates in linkage. From a linkage perspective, the rust compiler creates -two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary). -Native dynamic libraries and frameworks are propagated to the final artifact -boundary, while static libraries are not propagated at all. - -A few examples of how this model can be used are: - -* A native build dependency. Sometimes some C/C++ glue is needed when writing - some rust code, but distribution of the C/C++ code in a library format is just - a burden. In this case, the code will be archived into `libfoo.a` and then the - rust crate would declare a dependency via `#[link(name = "foo", kind = - "static")]`. - - Regardless of the flavor of output for the crate, the native static library - will be included in the output, meaning that distribution of the native static - library is not necessary. - -* A normal dynamic dependency. Common system libraries (like `readline`) are - available on a large number of systems, and often a static copy of these - libraries cannot be found. When this dependency is included in a rust crate, - partial targets (like rlibs) will not link to the library, but when the rlib - is included in a final target (like a binary), the native library will be - linked in. - -On OSX, frameworks behave with the same semantics as a dynamic library. - -# Unsafe blocks - -Some operations, like dereferencing unsafe pointers or calling functions that have been marked -unsafe are only allowed inside unsafe blocks. Unsafe blocks isolate unsafety and are a promise to -the compiler that the unsafety does not leak out of the block. - -Unsafe functions, on the other hand, advertise it to the world. An unsafe function is written like -this: - -``` -unsafe fn kaboom(ptr: *const i32) -> i32 { *ptr } -``` - -This function can only be called from an `unsafe` block or another `unsafe` function. - -# Accessing foreign globals - -Foreign APIs often export a global variable which could do something like track -global state. In order to access these variables, you declare them in `extern` -blocks with the `static` keyword: - -```no_run -# #![feature(libc)] -extern crate libc; - -#[link(name = "readline")] -extern { - static rl_readline_version: libc::c_int; -} - -fn main() { - println!("You have readline version {} installed.", - rl_readline_version as i32); -} -``` - -Alternatively, you may need to alter global state provided by a foreign -interface. To do this, statics can be declared with `mut` so we can mutate -them. - -```no_run -# #![feature(libc)] -extern crate libc; - -use std::ffi::CString; -use std::ptr; - -#[link(name = "readline")] -extern { - static mut rl_prompt: *const libc::c_char; -} - -fn main() { - let prompt = CString::new("[my-awesome-shell] $").unwrap(); - unsafe { - rl_prompt = prompt.as_ptr(); - - println!("{:?}", rl_prompt); - - rl_prompt = ptr::null(); - } -} -``` - -Note that all interaction with a `static mut` is unsafe, both reading and -writing. Dealing with global mutable state requires a great deal of care. - -# Foreign calling conventions - -Most foreign code exposes a C ABI, and Rust uses the platform's C calling convention by default when -calling foreign functions. Some foreign functions, most notably the Windows API, use other calling -conventions. Rust provides a way to tell the compiler which convention to use: - -``` -# #![feature(libc)] -extern crate libc; - -#[cfg(all(target_os = "win32", target_arch = "x86"))] -#[link(name = "kernel32")] -#[allow(non_snake_case)] -extern "stdcall" { - fn SetEnvironmentVariableA(n: *const u8, v: *const u8) -> libc::c_int; -} -# fn main() { } -``` - -This applies to the entire `extern` block. The list of supported ABI constraints -are: - -* `stdcall` -* `aapcs` -* `cdecl` -* `fastcall` -* `Rust` -* `rust-intrinsic` -* `system` -* `C` -* `win64` - -Most of the abis in this list are self-explanatory, but the `system` abi may -seem a little odd. This constraint selects whatever the appropriate ABI is for -interoperating with the target's libraries. For example, on win32 with a x86 -architecture, this means that the abi used would be `stdcall`. On x86_64, -however, windows uses the `C` calling convention, so `C` would be used. This -means that in our previous example, we could have used `extern "system" { ... }` -to define a block for all windows systems, not just x86 ones. - -# Interoperability with foreign code - -Rust guarantees that the layout of a `struct` is compatible with the platform's -representation in C only if the `#[repr(C)]` attribute is applied to it. -`#[repr(C, packed)]` can be used to lay out struct members without padding. -`#[repr(C)]` can also be applied to an enum. - -Rust's owned boxes (`Box`) use non-nullable pointers as handles which point -to the contained object. However, they should not be manually created because -they are managed by internal allocators. References can safely be assumed to be -non-nullable pointers directly to the type. However, breaking the borrow -checking or mutability rules is not guaranteed to be safe, so prefer using raw -pointers (`*`) if that's needed because the compiler can't make as many -assumptions about them. - -Vectors and strings share the same basic memory layout, and utilities are -available in the `vec` and `str` modules for working with C APIs. However, -strings are not terminated with `\0`. If you need a NUL-terminated string for -interoperability with C, you should use the `CString` type in the `std::ffi` -module. - -The standard library includes type aliases and function definitions for the C -standard library in the `libc` module, and Rust links against `libc` and `libm` -by default. - -# The "nullable pointer optimization" - -Certain types are defined to not be `null`. This includes references (`&T`, -`&mut T`), boxes (`Box`), and function pointers (`extern "abi" fn()`). -When interfacing with C, pointers that might be null are often used. -As a special case, a generic `enum` that contains exactly two variants, one of -which contains no data and the other containing a single field, is eligible -for the "nullable pointer optimization". When such an enum is instantiated -with one of the non-nullable types, it is represented as a single pointer, -and the non-data variant is represented as the null pointer. So -`Option c_int>` is how one represents a nullable -function pointer using the C ABI. - -# Calling Rust code from C - -You may wish to compile Rust code in a way so that it can be called from C. This is -fairly easy, but requires a few things: - -``` -#[no_mangle] -pub extern fn hello_rust() -> *const u8 { - "Hello, world!\0".as_ptr() -} -# fn main() {} -``` - -The `extern` makes this function adhere to the C calling convention, as -discussed above in "[Foreign Calling -Conventions](ffi.html#foreign-calling-conventions)". The `no_mangle` -attribute turns off Rust's name mangling, so that it is easier to link to. diff --git a/src/doc/trpl/for-loops.md b/src/doc/trpl/for-loops.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/functions.md b/src/doc/trpl/functions.md index 8e8ee8d63d626..e69de29bb2d1d 100644 --- a/src/doc/trpl/functions.md +++ b/src/doc/trpl/functions.md @@ -1,193 +0,0 @@ -% Functions - -You've already seen one function so far, the `main` function: - -```rust -fn main() { -} -``` - -This is the simplest possible function declaration. As we mentioned before, -`fn` says "this is a function," followed by the name, some parentheses because -this function takes no arguments, and then some curly braces to indicate the -body. Here's a function named `foo`: - -```rust -fn foo() { -} -``` - -So, what about taking arguments? Here's a function that prints a number: - -```rust -fn print_number(x: i32) { - println!("x is: {}", x); -} -``` - -Here's a complete program that uses `print_number`: - -```rust -fn main() { - print_number(5); -} - -fn print_number(x: i32) { - println!("x is: {}", x); -} -``` - -As you can see, function arguments work very similar to `let` declarations: -you add a type to the argument name, after a colon. - -Here's a complete program that adds two numbers together and prints them: - -```rust -fn main() { - print_sum(5, 6); -} - -fn print_sum(x: i32, y: i32) { - println!("sum is: {}", x + y); -} -``` - -You separate arguments with a comma, both when you call the function, as well -as when you declare it. - -Unlike `let`, you _must_ declare the types of function arguments. This does -not work: - -```{rust,ignore} -fn print_sum(x, y) { - println!("sum is: {}", x + y); -} -``` - -You get this error: - -```text -hello.rs:5:18: 5:19 expected one of `!`, `:`, or `@`, found `)` -hello.rs:5 fn print_number(x, y) { -``` - -This is a deliberate design decision. While full-program inference is possible, -languages which have it, like Haskell, often suggest that documenting your -types explicitly is a best-practice. We agree that forcing functions to declare -types while allowing for inference inside of function bodies is a wonderful -sweet spot between full inference and no inference. - -What about returning a value? Here's a function that adds one to an integer: - -```rust -fn add_one(x: i32) -> i32 { - x + 1 -} -``` - -Rust functions return exactly one value, and you declare the type after an -"arrow," which is a dash (`-`) followed by a greater-than sign (`>`). - -You'll note the lack of a semicolon here. If we added it in: - -```{rust,ignore} -fn add_one(x: i32) -> i32 { - x + 1; -} -``` - -We would get an error: - -```text -error: not all control paths return a value -fn add_one(x: i32) -> i32 { - x + 1; -} - -help: consider removing this semicolon: - x + 1; - ^ -``` - -Remember our earlier discussions about semicolons and `()`? Our function claims -to return an `i32`, but with a semicolon, it would return `()` instead. Rust -realizes this probably isn't what we want, and suggests removing the semicolon. - -This is very much like our `if` statement before: the result of the block -(`{}`) is the value of the expression. Other expression-oriented languages, -such as Ruby, work like this, but it's a bit unusual in the systems programming -world. When people first learn about this, they usually assume that it -introduces bugs. But because Rust's type system is so strong, and because unit -is its own unique type, we have never seen an issue where adding or removing a -semicolon in a return position would cause a bug. - -But what about early returns? Rust does have a keyword for that, `return`: - -```rust -fn foo(x: i32) -> i32 { - if x < 5 { return x; } - - x + 1 -} -``` - -Using a `return` as the last line of a function works, but is considered poor -style: - -```rust -fn foo(x: i32) -> i32 { - if x < 5 { return x; } - - return x + 1; -} -``` - -The previous definition without `return` may look a bit strange if you haven't -worked in an expression-based language before, but it becomes intuitive over -time. If this were production code, we wouldn't write it in that way anyway, -we'd write this: - -```rust -fn foo(x: i32) -> i32 { - if x < 5 { - x - } else { - x + 1 - } -} -``` - -Because `if` is an expression, and it's the only expression in this function, -the value will be the result of the `if`. - -## Diverging functions - -Rust has some special syntax for 'diverging functions', which are functions that -do not return: - -``` -fn diverges() -> ! { - panic!("This function never returns!"); -} -``` - -`panic!` is a macro, similar to `println!()` that we've already seen. Unlike -`println!()`, `panic!()` causes the current thread of execution to crash with -the given message. - -Because this function will cause a crash, it will never return, and so it has -the type '`!`', which is read "diverges." A diverging function can be used -as any type: - -```should_panic -# fn diverges() -> ! { -# panic!("This function never returns!"); -# } - -let x: i32 = diverges(); -let x: String = diverges(); -``` - -We don't have a good use for diverging functions yet, because they're used in -conjunction with other Rust features. But when you see `-> !` later, you'll -know what it's called. diff --git a/src/doc/trpl/generics.md b/src/doc/trpl/generics.md index 3e4e0a66eae05..e69de29bb2d1d 100644 --- a/src/doc/trpl/generics.md +++ b/src/doc/trpl/generics.md @@ -1,177 +0,0 @@ -% Generics - -Sometimes, when writing a function or data type, we may want it to work for -multiple types of arguments. For example, remember our `OptionalInt` type? - -```{rust} -enum OptionalInt { - Value(i32), - Missing, -} -``` - -If we wanted to also have an `OptionalFloat64`, we would need a new enum: - -```{rust} -enum OptionalFloat64 { - Valuef64(f64), - Missingf64, -} -``` - -This is really unfortunate. Luckily, Rust has a feature that gives us a better -way: generics. Generics are called *parametric polymorphism* in type theory, -which means that they are types or functions that have multiple forms (*poly* -is multiple, *morph* is form) over a given parameter (*parametric*). - -Anyway, enough with type theory declarations, let's check out the generic form -of `OptionalInt`. It is actually provided by Rust itself, and looks like this: - -```rust -enum Option { - Some(T), - None, -} -``` - -The `` part, which you've seen a few times before, indicates that this is -a generic data type. Inside the declaration of our enum, wherever we see a `T`, -we substitute that type for the same type used in the generic. Here's an -example of using `Option`, with some extra type annotations: - -```{rust} -let x: Option = Some(5); -``` - -In the type declaration, we say `Option`. Note how similar this looks to -`Option`. So, in this particular `Option`, `T` has the value of `i32`. On -the right-hand side of the binding, we do make a `Some(T)`, where `T` is `5`. -Since that's an `i32`, the two sides match, and Rust is happy. If they didn't -match, we'd get an error: - -```{rust,ignore} -let x: Option = Some(5); -// error: mismatched types: expected `core::option::Option`, -// found `core::option::Option<_>` (expected f64 but found integral variable) -``` - -That doesn't mean we can't make `Option`s that hold an `f64`! They just have to -match up: - -```{rust} -let x: Option = Some(5); -let y: Option = Some(5.0f64); -``` - -This is just fine. One definition, multiple uses. - -Generics don't have to only be generic over one type. Consider Rust's built-in -`Result` type: - -```{rust} -enum Result { - Ok(T), - Err(E), -} -``` - -This type is generic over _two_ types: `T` and `E`. By the way, the capital letters -can be any letter you'd like. We could define `Result` as: - -```{rust} -enum Result { - Ok(A), - Err(Z), -} -``` - -if we wanted to. Convention says that the first generic parameter should be -`T`, for 'type,' and that we use `E` for 'error.' Rust doesn't care, however. - -The `Result` type is intended to be used to return the result of a -computation, and to have the ability to return an error if it didn't work out. -Here's an example: - -```{rust} -let x: Result = Ok(2.3f64); -let y: Result = Err("There was an error.".to_string()); -``` - -This particular Result will return an `f64` if there's a success, and a -`String` if there's a failure. Let's write a function that uses `Result`: - -```{rust} -fn inverse(x: f64) -> Result { - if x == 0.0f64 { return Err("x cannot be zero!".to_string()); } - - Ok(1.0f64 / x) -} -``` - -We don't want to take the inverse of zero, so we check to make sure that we -weren't passed zero. If we were, then we return an `Err`, with a message. If -it's okay, we return an `Ok`, with the answer. - -Why does this matter? Well, remember how `match` does exhaustive matches? -Here's how this function gets used: - -```{rust} -# fn inverse(x: f64) -> Result { -# if x == 0.0f64 { return Err("x cannot be zero!".to_string()); } -# Ok(1.0f64 / x) -# } -let x = inverse(25.0f64); - -match x { - Ok(x) => println!("The inverse of 25 is {}", x), - Err(msg) => println!("Error: {}", msg), -} -``` - -The `match` enforces that we handle the `Err` case. In addition, because the -answer is wrapped up in an `Ok`, we can't just use the result without doing -the match: - -```{rust,ignore} -let x = inverse(25.0f64); -println!("{}", x + 2.0f64); // error: binary operation `+` cannot be applied - // to type `core::result::Result` -``` - -This function is great, but there's one other problem: it only works for 64 bit -floating point values. What if we wanted to handle 32 bit floating point as -well? We'd have to write this: - -```{rust} -fn inverse32(x: f32) -> Result { - if x == 0.0f32 { return Err("x cannot be zero!".to_string()); } - - Ok(1.0f32 / x) -} -``` - -Bummer. What we need is a *generic function*. Luckily, we can write one! -However, it won't _quite_ work yet. Before we get into that, let's talk syntax. -A generic version of `inverse` would look something like this: - -```{rust,ignore} -fn inverse(x: T) -> Result { - if x == 0.0 { return Err("x cannot be zero!".to_string()); } - - Ok(1.0 / x) -} -``` - -Just like how we had `Option`, we use a similar syntax for `inverse`. -We can then use `T` inside the rest of the signature: `x` has type `T`, and half -of the `Result` has type `T`. However, if we try to compile that example, we'll get -an error: - -```text -error: binary operation `==` cannot be applied to type `T` -``` - -Because `T` can be _any_ type, it may be a type that doesn't implement `==`, -and therefore, the first line would be wrong. What do we do? - -To fix this example, we need to learn about another Rust feature: traits. diff --git a/src/doc/trpl/getting-started.md b/src/doc/trpl/getting-started.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/glossary.md b/src/doc/trpl/glossary.md index 97898324847e4..e69de29bb2d1d 100644 --- a/src/doc/trpl/glossary.md +++ b/src/doc/trpl/glossary.md @@ -1,39 +0,0 @@ -% Glossary - -Not every Rustacean has a background in systems programming, nor in computer -science, so we've added explanations of terms that might be unfamiliar. - -### Arity - -Arity refers to the number of arguments a function or operation takes. - -```rust -let x = (2, 3); -let y = (4, 6); -let z = (8, 2, 6); -``` - -In the example above `x` and `y` have arity 2. `z` has arity 3. - -### Abstract Syntax Tree - -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 -structure of your program. For example, `2 + 3` can be turned into a tree: - -```text - + - / \ -2 3 -``` - -And `2 + (3 * 4)` would look like this: - -```text - + - / \ -2 * - / \ - 3 4 -``` diff --git a/src/doc/trpl/hello-cargo.md b/src/doc/trpl/hello-cargo.md index ae2a79bafecd5..e69de29bb2d1d 100644 --- a/src/doc/trpl/hello-cargo.md +++ b/src/doc/trpl/hello-cargo.md @@ -1,168 +0,0 @@ -% Hello, Cargo! - -[Cargo](http://crates.io) is a tool that Rustaceans use to help manage their -Rust projects. Cargo is currently in a pre-1.0 state, just like Rust, and so it -is still a work in progress. However, it is already good enough to use for many -Rust projects, and so it is assumed that Rust projects will use Cargo from the -beginning. - -Cargo manages three things: building your code, downloading the dependencies -your code needs, and building those dependencies. At first, your -program doesn't have any dependencies, so we'll only be using the first part of -its functionality. Eventually, we'll add more. Since we started off by using -Cargo, it'll be easy to add later. - -If you installed Rust via the official installers you will also have -Cargo. If you installed Rust some other way, you may want to [check -the Cargo -README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies) -for specific instructions about installing it. - -## Converting to Cargo - -Let's convert Hello World to Cargo. - -To Cargo-ify our project, we need to do two things: Make a `Cargo.toml` -configuration file, and put our source file in the right place. Let's -do that part first: - -```bash -$ mkdir src -$ mv main.rs src/main.rs -``` - -Cargo expects your source files to live inside a `src` directory. That leaves -the top level for other things, like READMEs, license information, and anything -not related to your code. Cargo helps us keep our projects nice and tidy. A -place for everything, and everything in its place. - -Next, our configuration file: - -```bash -$ editor Cargo.toml -``` - -Make sure to get this name right: you need the capital `C`! - -Put this inside: - -```toml -[package] - -name = "hello_world" -version = "0.0.1" -authors = [ "Your name " ] - -[[bin]] - -name = "hello_world" -``` - -This file is in the [TOML](https://github.com/toml-lang/toml) format. Let's let -it explain itself to you: - -> TOML aims to be a minimal configuration file format that's easy to read due -> to obvious semantics. TOML is designed to map unambiguously to a hash table. -> TOML should be easy to parse into data structures in a wide variety of -> languages. - -TOML is very similar to INI, but with some extra goodies. - -Anyway, there are two *tables* in this file: `package` and `bin`. The first -tells Cargo metadata about your package. The second tells Cargo that we're -interested in building a binary, not a library (though we could do both!), as -well as what it is named. - -Once you have this file in place, we should be ready to build! Try this: - -```bash -$ cargo build - Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world) -$ ./target/debug/hello_world -Hello, world! -``` - -Bam! We build our project with `cargo build`, and run it with -`./target/debug/hello_world`. This hasn't bought us a whole lot over our simple use -of `rustc`, but think about the future: when our project has more than one -file, we would need to call `rustc` more than once and pass it a bunch of options to -tell it to build everything together. With Cargo, as our project grows, we can -just `cargo build`, and it'll work the right way. When your project is finally -ready for release, you can use `cargo build --release` to compile your crates with -optimizations. - -You'll also notice that Cargo has created a new file: `Cargo.lock`. - -```toml -[root] -name = "hello_world" -version = "0.0.1" -``` - -This file is used by Cargo to keep track of dependencies in your application. -Right now, we don't have any, so it's a bit sparse. You won't ever need -to touch this file yourself, just let Cargo handle it. - -That's it! We've successfully built `hello_world` with Cargo. Even though our -program is simple, it's using much of the real tooling that you'll use for the -rest of your Rust career. - -## A New Project - -You don't have to go through this whole process every time you want to start a new -project! Cargo has the ability to make a bare-bones project directory in which you -can start developing right away. - -To start a new project with Cargo, use `cargo new`: - -```bash -$ cargo new hello_world --bin -``` - -We're passing `--bin` because we're making a binary program: if we -were making a library, we'd leave it off. - -Let's check out what Cargo has generated for us: - -```bash -$ cd hello_world -$ tree . -. -├── Cargo.toml -└── src - └── main.rs - -1 directory, 2 files -``` - -If you don't have the `tree` command, you can probably get it from your distro's package -manager. It's not necessary, but it's certainly useful. - -This is all we need to get started. First, let's check out `Cargo.toml`: - -```toml -[package] - -name = "hello_world" -version = "0.0.1" -authors = ["Your Name "] -``` - -Cargo has populated this file with reasonable defaults based off the arguments you gave -it and your `git` global configuration. You may notice that Cargo has also initialized -the `hello_world` directory as a `git` repository. - -Here's what's in `src/main.rs`: - -```rust -fn main() { - println!("Hello, world!"); -} -``` - -Cargo has generated a "Hello World!" for us, and you're ready to start coding! A -much more in-depth guide to Cargo can be found [here](http://doc.crates.io/guide.html). - -Now that you've got the tools down, let's actually learn more about the Rust -language itself. These are the basics that will serve you well through the rest -of your time with Rust. diff --git a/src/doc/trpl/hello-world.md b/src/doc/trpl/hello-world.md index f726f8627c929..e69de29bb2d1d 100644 --- a/src/doc/trpl/hello-world.md +++ b/src/doc/trpl/hello-world.md @@ -1,164 +0,0 @@ -% Hello, world! - -Now that you have Rust installed, let's write your first Rust program. It's -traditional to make your first program in any new language one that prints the -text "Hello, world!" to the screen. The nice thing about starting with such a -simple program is that you can verify that your compiler isn't just installed, -but also working properly. And printing information to the screen is a pretty -common thing to do. - -The first thing that we need to do is make a file to put our code in. I like -to make a `projects` directory in my home directory, and keep all my projects -there. Rust does not care where your code lives. - -This actually leads to one other concern we should address: this guide will -assume that you have basic familiarity with the command line. Rust does not -require that you know a whole ton about the command line, but until the -language is in a more finished state, IDE support is spotty. Rust makes no -specific demands on your editing tooling, or where your code lives. - -With that said, let's make a directory in our projects directory. - -```{bash} -$ mkdir ~/projects -$ cd ~/projects -$ mkdir hello_world -$ cd hello_world -``` - -If you're on Windows and not using PowerShell, the `~` may not work. Consult -the documentation for your shell for more details. - -Let's make a new source file next. I'm going to use the syntax `editor -filename` to represent editing a file in these examples, but you should use -whatever method you want. We'll call our file `main.rs`: - -```{bash} -$ editor main.rs -``` - -Rust files always end in a `.rs` extension. If you're using more than one word -in your filename, use an underscore. `hello_world.rs` rather than -`helloworld.rs`. - -Now that you've got your file open, type this in: - -```{rust} -fn main() { - println!("Hello, world!"); -} -``` - -Save the file, and then type this into your terminal window: - -```{bash} -$ rustc main.rs -$ ./main # or main.exe on Windows -Hello, world! -``` - -You can also run these examples on [play.rust-lang.org](http://play.rust-lang.org/) by clicking on the arrow that appears in the upper right of the example when you mouse over the code. - -Success! Let's go over what just happened in detail. - -```{rust} -fn main() { - -} -``` - -These lines define a *function* in Rust. The `main` function is special: -it's the beginning of every Rust program. The first line says "I'm declaring a -function named `main`, which takes no arguments and returns nothing." If there -were arguments, they would go inside the parentheses (`(` and `)`), and because -we aren't returning anything from this function, we can omit the return type -entirely. We'll get to it later. - -You'll also note that the function is wrapped in curly braces (`{` and `}`). -Rust requires these around all function bodies. It is also considered good -style to put the opening curly brace on the same line as the function -declaration, with one space in between. - -Next up is this line: - -```{rust} - println!("Hello, world!"); -``` - -This line does all of the work in our little program. There are a number of -details that are important here. The first is that it's indented with four -spaces, not tabs. Please configure your editor of choice to insert four spaces -with the tab key. We provide some [sample configurations for various -editors](https://github.com/rust-lang/rust/tree/master/src/etc/CONFIGS.md). - -The second point is the `println!()` part. This is calling a Rust *macro*, -which is how metaprogramming is done in Rust. If it were a function instead, it -would look like this: `println()`. For our purposes, we don't need to worry -about this difference. Just know that sometimes, you'll see a `!`, and that -means that you're calling a macro instead of a normal function. Rust implements -`println!` as a macro rather than a function for good reasons, but that's a -very advanced topic. You'll learn more when we talk about macros later. One -last thing to mention: Rust's macros are significantly different from C macros, -if you've used those. Don't be scared of using macros. We'll get to the details -eventually, you'll just have to trust us for now. - -Next, `"Hello, world!"` is a *string*. Strings are a surprisingly complicated -topic in a systems programming language, and this is a *statically allocated* -string. We will talk more about different kinds of allocation later. We pass -this string as an argument to `println!`, which prints the string to the -screen. Easy enough! - -Finally, the line ends with a semicolon (`;`). Rust is an *expression -oriented* language, which means that most things are expressions. The `;` is -used to indicate that this expression is over, and the next one is ready to -begin. Most lines of Rust code end with a `;`. We will cover this in-depth -later in the guide. - -Finally, actually *compiling* and *running* our program. We can compile -with our compiler, `rustc`, by passing it the name of our source file: - -```{bash} -$ rustc main.rs -``` - -This is similar to `gcc` or `clang`, if you come from a C or C++ background. Rust -will output a binary executable. You can see it with `ls`: - -```{bash} -$ ls -main main.rs -``` - -Or on Windows: - -```{bash} -$ dir -main.exe main.rs -``` - -There are now two files: our source code, with the `.rs` extension, and the -executable (`main.exe` on Windows, `main` everywhere else) - -```{bash} -$ ./main # or main.exe on Windows -``` - -This prints out our `Hello, world!` text to our terminal. - -If you come from a dynamically typed language like Ruby, Python, or JavaScript, -you may not be used to these two steps being separate. Rust is an -*ahead-of-time compiled language*, which means that you can compile a -program, give it to someone else, and they don't need to have Rust installed. -If you give someone a `.rb` or `.py` or `.js` file, they need to have a -Ruby/Python/JavaScript implementation installed, but you just need one command -to both compile and run your program. Everything is a tradeoff in language design, -and Rust has made its choice. - -Congratulations! You have officially written a Rust program. That makes you a -Rust programmer! Welcome. - -Next, I'd like to introduce you to another tool, Cargo, which is used to write -real-world Rust programs. Just using `rustc` is nice for simple things, but as -your project grows, you'll want something to help you manage all of the options -that it has, and to make it easy to share your code with other people and -projects. diff --git a/src/doc/trpl/if.md b/src/doc/trpl/if.md index 7dac49987d849..e69de29bb2d1d 100644 --- a/src/doc/trpl/if.md +++ b/src/doc/trpl/if.md @@ -1,155 +0,0 @@ -% If - -Rust's take on `if` is not particularly complex, but it's much more like the -`if` you'll find in a dynamically typed language than in a more traditional -systems language. So let's talk about it, to make sure you grasp the nuances. - -`if` is a specific form of a more general concept, the *branch*. The name comes -from a branch in a tree: a decision point, where depending on a choice, -multiple paths can be taken. - -In the case of `if`, there is one choice that leads down two paths: - -```rust -let x = 5; - -if x == 5 { - println!("x is five!"); -} -``` - -If we changed the value of `x` to something else, this line would not print. -More specifically, if the expression after the `if` evaluates to `true`, then -the block is executed. If it's `false`, then it is not. - -If you want something to happen in the `false` case, use an `else`: - -```{rust} -let x = 5; - -if x == 5 { - println!("x is five!"); -} else { - println!("x is not five :("); -} -``` - -If there is more than one case, use an `else if`: - -```rust -let x = 5; - -if x == 5 { - println!("x is five!"); -} else if x == 6 { - println!("x is six!"); -} else { - println!("x is not five or six :("); -} -``` - -This is all pretty standard. However, you can also do this: - - -```{rust} -let x = 5; - -let y = if x == 5 { - 10 -} else { - 15 -}; // y: i32 -``` - -Which we can (and probably should) write like this: - -```{rust} -let x = 5; - -let y = if x == 5 { 10 } else { 15 }; // y: i32 -``` - -This reveals two interesting things about Rust: it is an expression-based -language, and semicolons are different from semicolons in other 'curly brace -and semicolon'-based languages. These two things are related. - -## Expressions vs. Statements - -Rust is primarily an expression based language. There are only two kinds of -statements, and everything else is an expression. - -So what's the difference? Expressions return a value, and statements do not. -In many languages, `if` is a statement, and therefore, `let x = if ...` would -make no sense. But in Rust, `if` is an expression, which means that it returns -a value. We can then use this value to initialize the binding. - -Speaking of which, bindings are a kind of the first of Rust's two statements. -The proper name is a *declaration statement*. So far, `let` is the only kind -of declaration statement we've seen. Let's talk about that some more. - -In some languages, variable bindings can be written as expressions, not just -statements. Like Ruby: - -```{ruby} -x = y = 5 -``` - -In Rust, however, using `let` to introduce a binding is _not_ an expression. The -following will produce a compile-time error: - -```{ignore} -let x = (let y = 5); // expected identifier, found keyword `let` -``` - -The compiler is telling us here that it was expecting to see the beginning of -an expression, and a `let` can only begin a statement, not an expression. - -Note that assigning to an already-bound variable (e.g. `y = 5`) is still an -expression, although its value is not particularly useful. Unlike C, where an -assignment evaluates to the assigned value (e.g. `5` in the previous example), -in Rust the value of an assignment is the unit type `()` (which we'll cover later). - -The second kind of statement in Rust is the *expression statement*. Its -purpose is to turn any expression into a statement. In practical terms, Rust's -grammar expects statements to follow other statements. This means that you use -semicolons to separate expressions from each other. This means that Rust -looks a lot like most other languages that require you to use semicolons -at the end of every line, and you will see semicolons at the end of almost -every line of Rust code you see. - -What is this exception that makes us say "almost"? You saw it already, in this -code: - -```{rust} -let x = 5; - -let y: i32 = if x == 5 { 10 } else { 15 }; -``` - -Note that I've added the type annotation to `y`, to specify explicitly that I -want `y` to be an integer. - -This is not the same as this, which won't compile: - -```{ignore} -let x = 5; - -let y: i32 = if x == 5 { 10; } else { 15; }; -``` - -Note the semicolons after the 10 and 15. Rust will give us the following error: - -```text -error: mismatched types: expected `i32`, found `()` (expected i32, found ()) -``` - -We expected an integer, but we got `()`. `()` is pronounced *unit*, and is a -special type in Rust's type system. In Rust, `()` is _not_ a valid value for a -variable of type `i32`. It's only a valid value for variables of the type `()`, -which aren't very useful. Remember how we said statements don't return a value? -Well, that's the purpose of unit in this case. The semicolon turns any -expression into a statement by throwing away its value and returning unit -instead. - -There's one more time in which you won't see a semicolon at the end of a line -of Rust code. For that, we'll need our next concept: functions. diff --git a/src/doc/trpl/inline-assembly.md b/src/doc/trpl/inline-assembly.md index 1a4592f980fa7..e69de29bb2d1d 100644 --- a/src/doc/trpl/inline-assembly.md +++ b/src/doc/trpl/inline-assembly.md @@ -1,141 +0,0 @@ -% Inline Assembly - -For extremely low-level manipulations and performance reasons, one -might wish to control the CPU directly. Rust supports using inline -assembly to do this via the `asm!` macro. The syntax roughly matches -that of GCC & Clang: - -```ignore -asm!(assembly template - : output operands - : input operands - : clobbers - : options - ); -``` - -Any use of `asm` is feature gated (requires `#![feature(asm)]` on the -crate to allow) and of course requires an `unsafe` block. - -> **Note**: the examples here are given in x86/x86-64 assembly, but -> all platforms are supported. - -## Assembly template - -The `assembly template` is the only required parameter and must be a -literal string (i.e. `""`) - -``` -#![feature(asm)] - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn foo() { - unsafe { - asm!("NOP"); - } -} - -// other platforms -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -fn foo() { /* ... */ } - -fn main() { - // ... - foo(); - // ... -} -``` - -(The `feature(asm)` and `#[cfg]`s are omitted from now on.) - -Output operands, input operands, clobbers and options are all optional -but you must add the right number of `:` if you skip them: - -``` -# #![feature(asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# fn main() { unsafe { -asm!("xor %eax, %eax" - : - : - : "eax" - ); -# } } -``` - -Whitespace also doesn't matter: - -``` -# #![feature(asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# fn main() { unsafe { -asm!("xor %eax, %eax" ::: "eax"); -# } } -``` - -## Operands - -Input and output operands follow the same format: `: -"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand -expressions must be mutable lvalues: - -``` -# #![feature(asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn add(a: i32, b: i32) -> i32 { - let mut c = 0; - unsafe { - asm!("add $2, $0" - : "=r"(c) - : "0"(a), "r"(b) - ); - } - c -} -# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -# fn add(a: i32, b: i32) -> i32 { a + b } - -fn main() { - assert_eq!(add(3, 14159), 14162) -} -``` - -## Clobbers - -Some instructions modify registers which might otherwise have held -different values so we use the clobbers list to indicate to the -compiler not to assume any values loaded into those registers will -stay valid. - -``` -# #![feature(asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# fn main() { unsafe { -// Put the value 0x200 in eax -asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax"); -# } } -``` - -Input and output registers need not be listed since that information -is already communicated by the given constraints. Otherwise, any other -registers used either implicitly or explicitly should be listed. - -If the assembly changes the condition code register `cc` should be -specified as one of the clobbers. Similarly, if the assembly modifies -memory, `memory` should also be specified. - -## Options - -The last section, `options` is specific to Rust. The format is comma -separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to -specify some extra info about the inline assembly: - -Current valid options are: - -1. *volatile* - specifying this is analogous to - `__asm__ __volatile__ (...)` in gcc/clang. -2. *alignstack* - certain instructions expect the stack to be - aligned a certain way (i.e. SSE) and specifying this indicates to - the compiler to insert its usual stack alignment code -3. *intel* - use intel syntax instead of the default AT&T. - diff --git a/src/doc/trpl/installing-rust.md b/src/doc/trpl/installing-rust.md index c839688047aa6..e69de29bb2d1d 100644 --- a/src/doc/trpl/installing-rust.md +++ b/src/doc/trpl/installing-rust.md @@ -1,93 +0,0 @@ -% Installing Rust - -The first step to using Rust is to install it! There are a number of ways to -install Rust, but the easiest is to use the `rustup` script. If you're on -Linux or a Mac, all you need to do is this (note that you don't need to type -in the `$`s, they just indicate the start of each command): - -```bash -$ curl -sf -L https://static.rust-lang.org/rustup.sh | sudo sh -``` - -If you're concerned about the [potential insecurity](http://curlpipesh.tumblr.com/) of using `curl | sudo sh`, -please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script: - -```bash -$ curl -f -L https://static.rust-lang.org/rustup.sh -O -$ sudo sh rustup.sh -``` - -If you're on Windows, please download either the [32-bit -installer](https://static.rust-lang.org/dist/rust-1.0.0-beta-i686-pc-windows-gnu.exe) -or the [64-bit -installer](https://static.rust-lang.org/dist/rust-1.0.0-beta-x86_64-pc-windows-gnu.exe) -and run it. - -If you decide you don't want Rust anymore, we'll be a bit sad, but that's okay. -Not every programming language is great for everyone. Just run the uninstall -script: - -```bash -$ sudo /usr/local/lib/rustlib/uninstall.sh -``` - -If you used the Windows installer, just re-run the `.exe` and it will give you -an uninstall option. - -You can re-run this script any time you want to update Rust. Which, at this -point, is often. Rust is still pre-1.0, and so people assume that you're using -a very recent Rust. - -This brings me to one other point: some people, and somewhat rightfully so, get -very upset when we tell you to `curl | sudo sh`. And they should be! Basically, -when you do this, you are trusting that the good people who maintain Rust -aren't going to hack your computer and do bad things. That's a good instinct! -If you're one of those people, please check out the documentation on [building -Rust from Source](https://github.com/rust-lang/rust#building-from-source), or -[the official binary downloads](http://www.rust-lang.org/install.html). And we -promise that this method will not be the way to install Rust forever: it's just -the easiest way to keep people updated while Rust is in its alpha state. - -Oh, we should also mention the officially supported platforms: - -* Windows (7, 8, Server 2008 R2) -* Linux (2.6.18 or later, various distributions), x86 and x86-64 -* OSX 10.7 (Lion) or greater, x86 and x86-64 - -We extensively test Rust on these platforms, and a few others, too, like -Android. But these are the ones most likely to work, as they have the most -testing. - -Finally, a comment about Windows. Rust considers Windows to be a first-class -platform upon release, but if we're honest, the Windows experience isn't as -integrated as the Linux/OS X experience is. We're working on it! If anything -does not work, it is a bug. Please let us know if that happens. Each and every -commit is tested against Windows just like any other platform. - -If you've got Rust installed, you can open up a shell, and type this: - -```bash -$ rustc --version -``` - -You should see the version number, commit hash, commit date and build date: - -```bash -rustc 1.0.0-nightly (f11f3e7ba 2015-01-04) (built 2015-01-06) -``` - -If you did, Rust has been installed successfully! Congrats! - -This installer also installs a copy of the documentation locally, so you can -read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location. -On Windows, it's in a `share/doc` directory, inside wherever you installed Rust -to. - -If not, there are a number of places where you can get help. The easiest is -[the #rust IRC channel on irc.mozilla.org](irc://irc.mozilla.org/#rust), which -you can access through -[Mibbit](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust). Click -that link, and you'll be chatting with other Rustaceans (a silly nickname we -call ourselves), and we can help you out. Other great resources include [the -/r/rust subreddit](http://www.reddit.com/r/rust), and [Stack -Overflow](http://stackoverflow.com/questions/tagged/rust). diff --git a/src/doc/trpl/intermediate.md b/src/doc/trpl/intermediate.md deleted file mode 100644 index 73370a32231eb..0000000000000 --- a/src/doc/trpl/intermediate.md +++ /dev/null @@ -1,7 +0,0 @@ -% Intermediate - -This section contains individual chapters, which are self-contained. They focus -on specific topics, and can be read in any order. - -After reading "Intermediate," you will have a solid understanding of Rust, -and will be able to understand most Rust code and write more complex programs. diff --git a/src/doc/trpl/intrinsics.md b/src/doc/trpl/intrinsics.md index 25f7c54493188..e69de29bb2d1d 100644 --- a/src/doc/trpl/intrinsics.md +++ b/src/doc/trpl/intrinsics.md @@ -1,25 +0,0 @@ -% Intrinsics - -> **Note**: intrinsics will forever have an unstable interface, it is -> recommended to use the stable interfaces of libcore rather than intrinsics -> directly. - -These are imported as if they were FFI functions, with the special -`rust-intrinsic` ABI. For example, if one was in a freestanding -context, but wished to be able to `transmute` between types, and -perform efficient pointer arithmetic, one would import those functions -via a declaration like - -``` -# #![feature(intrinsics)] -# fn main() {} - -extern "rust-intrinsic" { - fn transmute(x: T) -> U; - - fn offset(dst: *const T, offset: isize) -> *const T; -} -``` - -As with any other FFI functions, these are always `unsafe` to call. - diff --git a/src/doc/trpl/iterators.md b/src/doc/trpl/iterators.md index eea575658b92c..e69de29bb2d1d 100644 --- a/src/doc/trpl/iterators.md +++ b/src/doc/trpl/iterators.md @@ -1,349 +0,0 @@ -% Iterators - -Let's talk about loops. - -Remember Rust's `for` loop? Here's an example: - -```rust -for x in 0..10 { - println!("{}", x); -} -``` - -Now that you know more Rust, we can talk in detail about how this works. -Ranges (the `0..10`) are 'iterators'. An iterator is something that we can -call the `.next()` method on repeatedly, and it gives us a sequence of things. - -Like this: - -```rust -let mut range = 0..10; - -loop { - match range.next() { - Some(x) => { - println!("{}", x); - }, - None => { break } - } -} -``` - -We make a mutable binding to the range, which is our iterator. We then `loop`, -with an inner `match`. This `match` is used on the result of `range.next()`, -which gives us a reference to the next value of the iterator. `next` returns an -`Option`, in this case, which will be `Some(i32)` when we have a value and -`None` once we run out. If we get `Some(i32)`, we print it out, and if we get -`None`, we `break` out of the loop. - -This code sample is basically the same as our `for` loop version. The `for` -loop is just a handy way to write this `loop`/`match`/`break` construct. - -`for` loops aren't the only thing that uses iterators, however. Writing your -own iterator involves implementing the `Iterator` trait. While doing that is -outside of the scope of this guide, Rust provides a number of useful iterators -to accomplish various tasks. Before we talk about those, we should talk about a -Rust anti-pattern. And that's using ranges like this. - -Yes, we just talked about how ranges are cool. But ranges are also very -primitive. For example, if you needed to iterate over the contents of a vector, -you may be tempted to write this: - -```rust -let nums = vec![1, 2, 3]; - -for i in 0..nums.len() { - println!("{}", nums[i]); -} -``` - -This is strictly worse than using an actual iterator. You can iterate over vectors -directly, so write this: - -```rust -let nums = vec![1, 2, 3]; - -for num in &nums { - println!("{}", num); -} -``` - -There are two reasons for this. First, this more directly expresses what we -mean. We iterate through the entire vector, rather than iterating through -indexes, and then indexing the vector. Second, this version is more efficient: -the first version will have extra bounds checking because it used indexing, -`nums[i]`. But since we yield a reference to each element of the vector in turn -with the iterator, there's no bounds checking in the second example. This is -very common with iterators: we can ignore unnecessary bounds checks, but still -know that we're safe. - -There's another detail here that's not 100% clear because of how `println!` -works. `num` is actually of type `&i32`. That is, it's a reference to an `i32`, -not an `i32` itself. `println!` handles the dereferencing for us, so we don't -see it. This code works fine too: - -```rust -let nums = vec![1, 2, 3]; - -for num in &nums { - println!("{}", *num); -} -``` - -Now we're explicitly dereferencing `num`. Why does `&nums` give us -references? Firstly, because we explicitly asked it to with -`&`. Secondly, if it gave us the data itself, we would have to be its -owner, which would involve making a copy of the data and giving us the -copy. With references, we're just borrowing a reference to the data, -and so it's just passing a reference, without needing to do the move. - -So, now that we've established that ranges are often not what you want, let's -talk about what you do want instead. - -There are three broad classes of things that are relevant here: iterators, -*iterator adapters*, and *consumers*. Here's some definitions: - -* *iterators* give you a sequence of values. -* *iterator adapters* operate on an iterator, producing a new iterator with a - different output sequence. -* *consumers* operate on an iterator, producing some final set of values. - -Let's talk about consumers first, since you've already seen an iterator, ranges. - -## Consumers - -A *consumer* operates on an iterator, returning some kind of value or values. -The most common consumer is `collect()`. This code doesn't quite compile, -but it shows the intention: - -```{rust,ignore} -let one_to_one_hundred = (1..101).collect(); -``` - -As you can see, we call `collect()` on our iterator. `collect()` takes -as many values as the iterator will give it, and returns a collection -of the results. So why won't this compile? Rust can't determine what -type of things you want to collect, and so you need to let it know. -Here's the version that does compile: - -```rust -let one_to_one_hundred = (1..101).collect::>(); -``` - -If you remember, the `::<>` syntax allows us to give a type hint, -and so we tell it that we want a vector of integers. You don't always -need to use the whole type, though. Using a `_` will let you provide -a partial hint: - -```rust -let one_to_one_hundred = (1..101).collect::>(); -``` - -This says "Collect into a `Vec`, please, but infer what the `T` is for me." -`_` is sometimes called a "type placeholder" for this reason. - -`collect()` is the most common consumer, but there are others too. `find()` -is one: - -```rust -let greater_than_forty_two = (0..100) - .find(|x| *x > 42); - -match greater_than_forty_two { - Some(_) => println!("We got some numbers!"), - None => println!("No numbers found :("), -} -``` - -`find` takes a closure, and works on a reference to each element of an -iterator. This closure returns `true` if the element is the element we're -looking for, and `false` otherwise. Because we might not find a matching -element, `find` returns an `Option` rather than the element itself. - -Another important consumer is `fold`. Here's what it looks like: - -```rust -let sum = (1..4).fold(0, |sum, x| sum + x); -``` - -`fold()` is a consumer that looks like this: -`fold(base, |accumulator, element| ...)`. It takes two arguments: the first -is an element called the *base*. The second is a closure that itself takes two -arguments: the first is called the *accumulator*, and the second is an -*element*. Upon each iteration, the closure is called, and the result is the -value of the accumulator on the next iteration. On the first iteration, the -base is the value of the accumulator. - -Okay, that's a bit confusing. Let's examine the values of all of these things -in this iterator: - -| base | accumulator | element | closure result | -|------|-------------|---------|----------------| -| 0 | 0 | 1 | 1 | -| 0 | 1 | 2 | 3 | -| 0 | 3 | 3 | 6 | - -We called `fold()` with these arguments: - -```rust -# (1..4) -.fold(0, |sum, x| sum + x); -``` - -So, `0` is our base, `sum` is our accumulator, and `x` is our element. On the -first iteration, we set `sum` to `0`, and `x` is the first element of `nums`, -`1`. We then add `sum` and `x`, which gives us `0 + 1 = 1`. On the second -iteration, that value becomes our accumulator, `sum`, and the element is -the second element of the array, `2`. `1 + 2 = 3`, and so that becomes -the value of the accumulator for the last iteration. On that iteration, -`x` is the last element, `3`, and `3 + 3 = 6`, which is our final -result for our sum. `1 + 2 + 3 = 6`, and that's the result we got. - -Whew. `fold` can be a bit strange the first few times you see it, but once it -clicks, you can use it all over the place. Any time you have a list of things, -and you want a single result, `fold` is appropriate. - -Consumers are important due to one additional property of iterators we haven't -talked about yet: laziness. Let's talk some more about iterators, and you'll -see why consumers matter. - -## Iterators - -As we've said before, an iterator is something that we can call the -`.next()` method on repeatedly, and it gives us a sequence of things. -Because you need to call the method, this means that iterators -are *lazy* and don't need to generate all of the values upfront. -This code, for example, does not actually generate the numbers -`1-100`, and just creates a value that represents the sequence: - -```rust -let nums = 1..100; -``` - -Since we didn't do anything with the range, it didn't generate the sequence. -Let's add the consumer: - -```rust -let nums = (1..100).collect::>(); -``` - -Now, `collect()` will require that the range gives it some numbers, and so -it will do the work of generating the sequence. - -Ranges are one of two basic iterators that you'll see. The other is `iter()`. -`iter()` can turn a vector into a simple iterator that gives you each element -in turn: - -```rust -let nums = [1, 2, 3]; - -for num in nums.iter() { - println!("{}", num); -} -``` - -These two basic iterators should serve you well. There are some more -advanced iterators, including ones that are infinite. Like using range syntax -and `step_by`: - -```rust -# #![feature(step_by)] -(1..).step_by(5); -``` - -This iterator counts up from one, adding five each time. It will give -you a new integer every time, forever (well, technically, until it reaches the -maximum number representable by an `i32`). But since iterators are lazy, -that's okay! You probably don't want to use `collect()` on it, though... - -That's enough about iterators. Iterator adapters are the last concept -we need to talk about with regards to iterators. Let's get to it! - -## Iterator adapters - -*Iterator adapters* take an iterator and modify it somehow, producing -a new iterator. The simplest one is called `map`: - -```{rust,ignore} -(1..100).map(|x| x + 1); -``` - -`map` is called upon another iterator, and produces a new iterator where each -element reference has the closure it's been given as an argument called on it. -So this would give us the numbers from `2-100`. Well, almost! If you -compile the example, you'll get a warning: - -```text -warning: unused result which must be used: iterator adaptors are lazy and - do nothing unless consumed, #[warn(unused_must_use)] on by default -(1..100).map(|x| x + 1); - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -``` - -Laziness strikes again! That closure will never execute. This example -doesn't print any numbers: - -```{rust,ignore} -(1..100).map(|x| println!("{}", x)); -``` - -If you are trying to execute a closure on an iterator for its side effects, -just use `for` instead. - -There are tons of interesting iterator adapters. `take(n)` will return an -iterator over the next `n` elements of the original iterator. Note that this -has no side effect on the original iterator. Let's try it out with our infinite -iterator from before: - -```rust -# #![feature(step_by)] -for i in (1..).step_by(5).take(5) { - println!("{}", i); -} -``` - -This will print - -```text -1 -6 -11 -16 -21 -``` - -`filter()` is an adapter that takes a closure as an argument. This closure -returns `true` or `false`. The new iterator `filter()` produces -only the elements that that closure returns `true` for: - -```rust -for i in (1..100).filter(|&x| x % 2 == 0) { - println!("{}", i); -} -``` - -This will print all of the even numbers between one and a hundred. -(Note that because `filter` doesn't consume the elements that are -being iterated over, it is passed a reference to each element, and -thus the filter predicate uses the `&x` pattern to extract the integer -itself.) - -You can chain all three things together: start with an iterator, adapt it -a few times, and then consume the result. Check it out: - -```rust -(1..1000) - .filter(|&x| x % 2 == 0) - .filter(|&x| x % 3 == 0) - .take(5) - .collect::>(); -``` - -This will give you a vector containing `6`, `12`, `18`, `24`, and `30`. - -This is just a small taste of what iterators, iterator adapters, and consumers -can help you with. There are a number of really useful iterators, and you can -write your own as well. Iterators provide a safe, efficient way to manipulate -all kinds of lists. They're a little unusual at first, but if you play with -them, you'll get hooked. For a full list of the different iterators and -consumers, check out the [iterator module documentation](../std/iter/index.html). diff --git a/src/doc/trpl/lang-items.md b/src/doc/trpl/lang-items.md index 5c27c03e8e0b2..e69de29bb2d1d 100644 --- a/src/doc/trpl/lang-items.md +++ b/src/doc/trpl/lang-items.md @@ -1,79 +0,0 @@ -% Lang items - -> **Note**: lang items are often provided by crates in the Rust distribution, -> and lang items themselves have an unstable interface. It is recommended to use -> officially distributed crates instead of defining your own lang items. - -The `rustc` compiler has certain pluggable operations, that is, -functionality that isn't hard-coded into the language, but is -implemented in libraries, with a special marker to tell the compiler -it exists. The marker is the attribute `#[lang="..."]` and there are -various different values of `...`, i.e. various different 'lang -items'. - -For example, `Box` pointers require two lang items, one for allocation -and one for deallocation. A freestanding program that uses the `Box` -sugar for dynamic allocations via `malloc` and `free`: - -``` -#![feature(lang_items, box_syntax, start, no_std, libc)] -#![no_std] - -extern crate libc; - -extern { - fn abort() -> !; -} - -#[lang = "owned_box"] -pub struct Box(*mut T); - -#[lang="exchange_malloc"] -unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { - let p = libc::malloc(size as libc::size_t) as *mut u8; - - // malloc failed - if p as usize == 0 { - abort(); - } - - p -} -#[lang="exchange_free"] -unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) { - libc::free(ptr as *mut libc::c_void) -} - -#[start] -fn main(argc: isize, argv: *const *const u8) -> isize { - let x = box 1; - - 0 -} - -#[lang = "stack_exhausted"] extern fn stack_exhausted() {} -#[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -``` - -Note the use of `abort`: the `exchange_malloc` lang item is assumed to -return a valid pointer, and so needs to do the check internally. - -Other features provided by lang items include: - -- overloadable operators via traits: the traits corresponding to the - `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all - marked with lang items; those specific four are `eq`, `ord`, - `deref`, and `add` respectively. -- stack unwinding and general failure; the `eh_personality`, `fail` - and `fail_bounds_checks` lang items. -- the traits in `std::marker` used to indicate types of - various kinds; lang items `send`, `sync` and `copy`. -- the marker types and variance indicators found in - `std::marker`; lang items `covariant_type`, - `contravariant_lifetime`, etc. - -Lang items are loaded lazily by the compiler; e.g. if one never uses -`Box` then there is no need to define functions for `exchange_malloc` -and `exchange_free`. `rustc` will emit an error when an item is needed -but not found in the current crate or any that it depends on. diff --git a/src/doc/trpl/learn-rust.md b/src/doc/trpl/learn-rust.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/link-args.md b/src/doc/trpl/link-args.md index ee5159afb8e6f..e69de29bb2d1d 100644 --- a/src/doc/trpl/link-args.md +++ b/src/doc/trpl/link-args.md @@ -1,25 +0,0 @@ -% Link args - -There is one other way to tell rustc how to customize linking, and that is via -the `link_args` attribute. This attribute is applied to `extern` blocks and -specifies raw flags which need to get passed to the linker when producing an -artifact. An example usage would be: - -``` no_run -#![feature(link_args)] - -#[link_args = "-foo -bar -baz"] -extern {} -# fn main() {} -``` - -Note that this feature is currently hidden behind the `feature(link_args)` gate -because this is not a sanctioned way of performing linking. Right now rustc -shells out to the system linker, so it makes sense to provide extra command line -arguments, but this will not always be the case. In the future rustc may use -LLVM directly to link native libraries in which case `link_args` will have no -meaning. - -It is highly recommended to *not* use this attribute, and rather use the more -formal `#[link(...)]` attribute on `extern` blocks instead. - diff --git a/src/doc/trpl/lol.txt b/src/doc/trpl/lol.txt new file mode 100644 index 0000000000000..ea7600113641b --- /dev/null +++ b/src/doc/trpl/lol.txt @@ -0,0 +1 @@ +getting-started.md installing-rust.md hello-world.md hello-cargo.md learn-rust.md effective-rust.md the-stack-and-the-heap.md debug-and-display.md testing.md documentation.md iterators.md concurrency.md error-handling.md ffi.md deref-coercions.md syntax-and-semantics.md variable-bindings.md primitive-types.md functions.md comments.md structs.md mutability.md method-syntax.md enums.md if.md match.md patterns.md for-loops.md while-loops.md ownership.md references-and-borrowing.md lifetimes.md move-semantics.md drop.md vectors.md arrays.md slices.md strings.md traits.md operators-and-overloading.md generics.md trait-objects.md closures.md ufcs.md crates-and-modules.md static.md const.md tuples.md tuple-structs.md attributes.md conditional-compilation.md type-aliases.md casting-between-types.md associated-types.md unsized-types.md macros.md unsafe-code.md nightly-rust.md plugins.md inline-assembly.md no-stdlib.md intrinsics.md lang-items.md link-args.md benchmark-tests.md box-syntax-and-patterns.md glossary.md diff --git a/src/doc/trpl/looping.md b/src/doc/trpl/looping.md deleted file mode 100644 index 28f02b1ffe152..0000000000000 --- a/src/doc/trpl/looping.md +++ /dev/null @@ -1,133 +0,0 @@ -% Looping - -Looping is the last basic construct that we haven't learned yet in Rust. Rust has -two main looping constructs: `for` and `while`. - -## `for` - -The `for` loop is used to loop a particular number of times. Rust's `for` loops -work a bit differently than in other systems languages, however. Rust's `for` -loop doesn't look like this "C-style" `for` loop: - -```{c} -for (x = 0; x < 10; x++) { - printf( "%d\n", x ); -} -``` - -Instead, it looks like this: - -```{rust} -for x in 0..10 { - println!("{}", x); // x: i32 -} -``` - -In slightly more abstract terms, - -```{ignore} -for var in expression { - code -} -``` - -The expression is an iterator, which we will discuss in more depth later in the -guide. The iterator gives back a series of elements. Each element is one -iteration of the loop. That value is then bound to the name `var`, which is -valid for the loop body. Once the body is over, the next value is fetched from -the iterator, and we loop another time. When there are no more values, the -`for` loop is over. - -In our example, `0..10` is an expression that takes a start and an end position, -and gives an iterator over those values. The upper bound is exclusive, though, -so our loop will print `0` through `9`, not `10`. - -Rust does not have the "C-style" `for` loop on purpose. Manually controlling -each element of the loop is complicated and error prone, even for experienced C -developers. - -We'll talk more about `for` when we cover *iterators*, later in the Guide. - -## `while` - -The other kind of looping construct in Rust is the `while` loop. It looks like -this: - -```{rust} -let mut x = 5; // mut x: u32 -let mut done = false; // mut done: bool - -while !done { - x += x - 3; - println!("{}", x); - if x % 5 == 0 { done = true; } -} -``` - -`while` loops are the correct choice when you're not sure how many times -you need to loop. - -If you need an infinite loop, you may be tempted to write this: - -```{rust,ignore} -while true { -``` - -However, Rust has a dedicated keyword, `loop`, to handle this case: - -```{rust,ignore} -loop { -``` - -Rust's control-flow analysis treats this construct differently than a -`while true`, since we know that it will always loop. The details of what -that _means_ aren't super important to understand at this stage, but in -general, the more information we can give to the compiler, the better it -can do with safety and code generation, so you should always prefer -`loop` when you plan to loop infinitely. - -## Ending iteration early - -Let's take a look at that `while` loop we had earlier: - -```{rust} -let mut x = 5; -let mut done = false; - -while !done { - x += x - 3; - println!("{}", x); - if x % 5 == 0 { done = true; } -} -``` - -We had to keep a dedicated `mut` boolean variable binding, `done`, to know -when we should exit out of the loop. Rust has two keywords to help us with -modifying iteration: `break` and `continue`. - -In this case, we can write the loop in a better way with `break`: - -```{rust} -let mut x = 5; - -loop { - x += x - 3; - println!("{}", x); - if x % 5 == 0 { break; } -} -``` - -We now loop forever with `loop` and use `break` to break out early. - -`continue` is similar, but instead of ending the loop, goes to the next -iteration. This will only print the odd numbers: - -```{rust} -for x in 0..10 { - if x % 2 == 0 { continue; } - - println!("{}", x); -} -``` - -Both `continue` and `break` are valid in both kinds of loops. diff --git a/src/doc/trpl/macros.md b/src/doc/trpl/macros.md index 7e19ec94ee745..e69de29bb2d1d 100644 --- a/src/doc/trpl/macros.md +++ b/src/doc/trpl/macros.md @@ -1,432 +0,0 @@ -% Macros - -By now you've learned about many of the tools Rust provides for abstracting and -reusing code. These units of code reuse have a rich semantic structure. For -example, functions have a type signature, type parameters have trait bounds, -and overloaded functions must belong to a particular trait. - -This structure means that Rust's core abstractions have powerful compile-time -correctness checking. But this comes at the price of reduced flexibility. If -you visually identify a pattern of repeated code, you may find it's difficult -or cumbersome to express that pattern as a generic function, a trait, or -anything else within Rust's semantics. - -Macros allow us to abstract at a *syntactic* level. A macro invocation is -shorthand for an "expanded" syntactic form. This expansion happens early in -compilation, before any static checking. As a result, macros can capture many -patterns of code reuse that Rust's core abstractions cannot. - -The drawback is that macro-based code can be harder to understand, because -fewer of the built-in rules apply. Like an ordinary function, a well-behaved -macro can be used without understanding its implementation. However, it can be -difficult to design a well-behaved macro! Additionally, compiler errors in -macro code are harder to interpret, because they describe problems in the -expanded code, not the source-level form that developers use. - -These drawbacks make macros something of a "feature of last resort". That's not -to say that macros are bad; they are part of Rust because sometimes they're -needed for truly concise, well-abstracted code. Just keep this tradeoff in -mind. - -# Defining a macro - -You may have seen the `vec!` macro, used to initialize a [vector][] with any -number of elements. - -[vector]: arrays-vectors-and-slices.html - -```rust -let x: Vec = vec![1, 2, 3]; -# assert_eq!(x, [1, 2, 3]); -``` - -This can't be an ordinary function, because it takes any number of arguments. -But we can imagine it as syntactic shorthand for - -```rust -let x: Vec = { - let mut temp_vec = Vec::new(); - temp_vec.push(1); - temp_vec.push(2); - temp_vec.push(3); - temp_vec -}; -# assert_eq!(x, [1, 2, 3]); -``` - -We can implement this shorthand, using a macro: [^actual] - -[^actual]: The actual definition of `vec!` in libcollections differs from the - one presented here, for reasons of efficiency and reusability. Some - of these are mentioned in the [advanced macros chapter][]. - -```rust -macro_rules! vec { - ( $( $x:expr ),* ) => { - { - let mut temp_vec = Vec::new(); - $( - temp_vec.push($x); - )* - temp_vec - } - }; -} -# fn main() { -# assert_eq!(vec![1,2,3], [1, 2, 3]); -# } -``` - -Whoa, that's a lot of new syntax! Let's break it down. - -```ignore -macro_rules! vec { ... } -``` - -This says we're defining a macro named `vec`, much as `fn vec` would define a -function named `vec`. In prose, we informally write a macro's name with an -exclamation point, e.g. `vec!`. The exclamation point is part of the invocation -syntax and serves to distinguish a macro from an ordinary function. - -## Matching - -The macro is defined through a series of *rules*, which are pattern-matching -cases. Above, we had - -```ignore -( $( $x:expr ),* ) => { ... }; -``` - -This is like a `match` expression arm, but the matching happens on Rust syntax -trees, at compile time. The semicolon is optional on the last (here, only) -case. The "pattern" on the left-hand side of `=>` is known as a *matcher*. -These have [their own little grammar] within the language. - -[their own little grammar]: ../reference.html#macros - -The matcher `$x:expr` will match any Rust expression, binding that syntax tree -to the *metavariable* `$x`. The identifier `expr` is a *fragment specifier*; -the full possibilities are enumerated in the [advanced macros chapter][]. -Surrounding the matcher with `$(...),*` will match zero or more expressions, -separated by commas. - -Aside from the special matcher syntax, any Rust tokens that appear in a matcher -must match exactly. For example, - -```rust -macro_rules! foo { - (x => $e:expr) => (println!("mode X: {}", $e)); - (y => $e:expr) => (println!("mode Y: {}", $e)); -} - -fn main() { - foo!(y => 3); -} -``` - -will print - -```text -mode Y: 3 -``` - -With - -```rust,ignore -foo!(z => 3); -``` - -we get the compiler error - -```text -error: no rules expected the token `z` -``` - -## Expansion - -The right-hand side of a macro rule is ordinary Rust syntax, for the most part. -But we can splice in bits of syntax captured by the matcher. From the original -example: - -```ignore -$( - temp_vec.push($x); -)* -``` - -Each matched expression `$x` will produce a single `push` statement in the -macro expansion. The repetition in the expansion proceeds in "lockstep" with -repetition in the matcher (more on this in a moment). - -Because `$x` was already declared as matching an expression, we don't repeat -`:expr` on the right-hand side. Also, we don't include a separating comma as -part of the repetition operator. Instead, we have a terminating semicolon -within the repeated block. - -Another detail: the `vec!` macro has *two* pairs of braces on the right-hand -side. They are often combined like so: - -```ignore -macro_rules! foo { - () => {{ - ... - }} -} -``` - -The outer braces are part of the syntax of `macro_rules!`. In fact, you can use -`()` or `[]` instead. They simply delimit the right-hand side as a whole. - -The inner braces are part of the expanded syntax. Remember, the `vec!` macro is -used in an expression context. To write an expression with multiple statements, -including `let`-bindings, we use a block. If your macro expands to a single -expression, you don't need this extra layer of braces. - -Note that we never *declared* that the macro produces an expression. In fact, -this is not determined until we use the macro as an expression. With care, you -can write a macro whose expansion works in several contexts. For example, -shorthand for a data type could be valid as either an expression or a pattern. - -## Repetition - -The repetition operator follows two principal rules: - -1. `$(...)*` walks through one "layer" of repetitions, for all of the `$name`s - it contains, in lockstep, and -2. each `$name` must be under at least as many `$(...)*`s as it was matched - against. If it is under more, it'll be duplicated, as appropriate. - -This baroque macro illustrates the duplication of variables from outer -repetition levels. - -```rust -macro_rules! o_O { - ( - $( - $x:expr; [ $( $y:expr ),* ] - );* - ) => { - &[ $($( $x + $y ),*),* ] - } -} - -fn main() { - let a: &[i32] - = o_O!(10; [1, 2, 3]; - 20; [4, 5, 6]); - - assert_eq!(a, [11, 12, 13, 24, 25, 26]); -} -``` - -That's most of the matcher syntax. These examples use `$(...)*`, which is a -"zero or more" match. Alternatively you can write `$(...)+` for a "one or -more" match. Both forms optionally include a separator, which can be any token -except `+` or `*`. - -This system is based on -"[Macro-by-Example](http://www.cs.indiana.edu/ftp/techreports/TR206.pdf)" -(PDF link). - -# Hygiene - -Some languages implement macros using simple text substitution, which leads to -various problems. For example, this C program prints `13` instead of the -expected `25`. - -```text -#define FIVE_TIMES(x) 5 * x - -int main() { - printf("%d\n", FIVE_TIMES(2 + 3)); - return 0; -} -``` - -After expansion we have `5 * 2 + 3`, and multiplication has greater precedence -than addition. If you've used C macros a lot, you probably know the standard -idioms for avoiding this problem, as well as five or six others. In Rust, we -don't have to worry about it. - -```rust -macro_rules! five_times { - ($x:expr) => (5 * $x); -} - -fn main() { - assert_eq!(25, five_times!(2 + 3)); -} -``` - -The metavariable `$x` is parsed as a single expression node, and keeps its -place in the syntax tree even after substitution. - -Another common problem in macro systems is *variable capture*. Here's a C -macro, using [a GNU C extension] to emulate Rust's expression blocks. - -[a GNU C extension]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html - -```text -#define LOG(msg) ({ \ - int state = get_log_state(); \ - if (state > 0) { \ - printf("log(%d): %s\n", state, msg); \ - } \ -}) -``` - -Here's a simple use case that goes terribly wrong: - -```text -const char *state = "reticulating splines"; -LOG(state) -``` - -This expands to - -```text -const char *state = "reticulating splines"; -int state = get_log_state(); -if (state > 0) { - printf("log(%d): %s\n", state, state); -} -``` - -The second variable named `state` shadows the first one. This is a problem -because the print statement should refer to both of them. - -The equivalent Rust macro has the desired behavior. - -```rust -# fn get_log_state() -> i32 { 3 } -macro_rules! log { - ($msg:expr) => {{ - let state: i32 = get_log_state(); - if state > 0 { - println!("log({}): {}", state, $msg); - } - }}; -} - -fn main() { - let state: &str = "reticulating splines"; - log!(state); -} -``` - -This works because Rust has a [hygienic macro system][]. Each macro expansion -happens in a distinct *syntax context*, and each variable is tagged with the -syntax context where it was introduced. It's as though the variable `state` -inside `main` is painted a different "color" from the variable `state` inside -the macro, and therefore they don't conflict. - -[hygienic macro system]: http://en.wikipedia.org/wiki/Hygienic_macro - -This also restricts the ability of macros to introduce new bindings at the -invocation site. Code such as the following will not work: - -```rust,ignore -macro_rules! foo { - () => (let x = 3); -} - -fn main() { - foo!(); - println!("{}", x); -} -``` - -Instead you need to pass the variable name into the invocation, so it's tagged -with the right syntax context. - -```rust -macro_rules! foo { - ($v:ident) => (let $v = 3); -} - -fn main() { - foo!(x); - println!("{}", x); -} -``` - -This holds for `let` bindings and loop labels, but not for [items][]. -So the following code does compile: - -```rust -macro_rules! foo { - () => (fn x() { }); -} - -fn main() { - foo!(); - x(); -} -``` - -[items]: ../reference.html#items - -# Recursive macros - -A macro's expansion can include more macro invocations, including invocations -of the very same macro being expanded. These recursive macros are useful for -processing tree-structured input, as illustrated by this (simplistic) HTML -shorthand: - -```rust -# #![allow(unused_must_use)] -macro_rules! write_html { - ($w:expr, ) => (()); - - ($w:expr, $e:tt) => (write!($w, "{}", $e)); - - ($w:expr, $tag:ident [ $($inner:tt)* ] $($rest:tt)*) => {{ - write!($w, "<{}>", stringify!($tag)); - write_html!($w, $($inner)*); - write!($w, "", stringify!($tag)); - write_html!($w, $($rest)*); - }}; -} - -fn main() { -# // FIXME(#21826) - use std::fmt::Write; - let mut out = String::new(); - - write_html!(&mut out, - html[ - head[title["Macros guide"]] - body[h1["Macros are the best!"]] - ]); - - assert_eq!(out, - "Macros guide\ -

Macros are the best!

"); -} -``` - -# Debugging macro code - -To see the results of expanding macros, run `rustc --pretty expanded`. The -output represents a whole crate, so you can also feed it back in to `rustc`, -which will sometimes produce better error messages than the original -compilation. Note that the `--pretty expanded` output may have a different -meaning if multiple variables of the same name (but different syntax contexts) -are in play in the same scope. In this case `--pretty expanded,hygiene` will -tell you about the syntax contexts. - -`rustc` provides two syntax extensions that help with macro debugging. For now, -they are unstable and require feature gates. - -* `log_syntax!(...)` will print its arguments to standard output, at compile - time, and "expand" to nothing. - -* `trace_macros!(true)` will enable a compiler message every time a macro is - expanded. Use `trace_macros!(false)` later in expansion to turn it off. - -# Further reading - -The [advanced macros chapter][] goes into more detail about macro syntax. It -also describes how to share macros between different modules or crates. - -[advanced macros chapter]: advanced-macros.html diff --git a/src/doc/trpl/match.md b/src/doc/trpl/match.md index 73bc775a1b290..e69de29bb2d1d 100644 --- a/src/doc/trpl/match.md +++ b/src/doc/trpl/match.md @@ -1,156 +0,0 @@ -% Match - -Often, a simple `if`/`else` isn't enough, because you have more than two -possible options. Also, `else` conditions can get incredibly complicated, so -what's the solution? - -Rust has a keyword, `match`, that allows you to replace complicated `if`/`else` -groupings with something more powerful. Check it out: - -```{rust} -let x = 5; - -match x { - 1 => println!("one"), - 2 => println!("two"), - 3 => println!("three"), - 4 => println!("four"), - 5 => println!("five"), - _ => println!("something else"), -} -``` - -`match` takes an expression and then branches based on its value. Each *arm* of -the branch is of the form `val => expression`. When the value matches, that arm's -expression will be evaluated. It's called `match` because of the term 'pattern -matching', which `match` is an implementation of. - -So what's the big advantage here? Well, there are a few. First of all, `match` -enforces *exhaustiveness checking*. Do you see that last arm, the one with the -underscore (`_`)? If we remove that arm, Rust will give us an error: - -```text -error: non-exhaustive patterns: `_` not covered -``` - -In other words, Rust is trying to tell us we forgot a value. Because `x` is an -integer, Rust knows that it can have a number of different values – for example, -`6`. Without the `_`, however, there is no arm that could match, and so Rust refuses -to compile. `_` acts like a *catch-all arm*. If none of the other arms match, -the arm with `_` will, and since we have this catch-all arm, we now have an arm -for every possible value of `x`, and so our program will compile successfully. - -`match` statements also destructure enums, as well. Remember this code from the -section on enums? - -```{rust} -use std::cmp::Ordering; - -fn cmp(a: i32, b: i32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} - -fn main() { - let x = 5; - let y = 10; - - let ordering = cmp(x, y); - - if ordering == Ordering::Less { - println!("less"); - } else if ordering == Ordering::Greater { - println!("greater"); - } else if ordering == Ordering::Equal { - println!("equal"); - } -} -``` - -We can re-write this as a `match`: - -```{rust} -use std::cmp::Ordering; - -fn cmp(a: i32, b: i32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} - -fn main() { - let x = 5; - let y = 10; - - match cmp(x, y) { - Ordering::Less => println!("less"), - Ordering::Greater => println!("greater"), - Ordering::Equal => println!("equal"), - } -} -``` - -This version has way less noise, and it also checks exhaustively to make sure -that we have covered all possible variants of `Ordering`. With our `if`/`else` -version, if we had forgotten the `Greater` case, for example, our program would -have happily compiled. If we forget in the `match`, it will not. Rust helps us -make sure to cover all of our bases. - -`match` expressions also allow us to get the values contained in an `enum` -(also known as destructuring) as follows: - -```{rust} -enum OptionalInt { - Value(i32), - Missing, -} - -fn main() { - let x = OptionalInt::Value(5); - let y = OptionalInt::Missing; - - match x { - OptionalInt::Value(n) => println!("x is {}", n), - OptionalInt::Missing => println!("x is missing!"), - } - - match y { - OptionalInt::Value(n) => println!("y is {}", n), - OptionalInt::Missing => println!("y is missing!"), - } -} -``` - -That is how you can get and use the values contained in `enum`s. -It can also allow us to handle errors or unexpected computations; for example, a -function that is not guaranteed to be able to compute a result (an `i32` here) -could return an `OptionalInt`, and we would handle that value with a `match`. -As you can see, `enum` and `match` used together are quite useful! - -`match` is also an expression, which means we can use it on the right-hand -side of a `let` binding or directly where an expression is used. We could -also implement the previous example like this: - -```{rust} -use std::cmp::Ordering; - -fn cmp(a: i32, b: i32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} - -fn main() { - let x = 5; - let y = 10; - - println!("{}", match cmp(x, y) { - Ordering::Less => "less", - Ordering::Greater => "greater", - Ordering::Equal => "equal", - }); -} -``` - -Sometimes, it's a nice pattern. diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md index f6eacd0a84288..e69de29bb2d1d 100644 --- a/src/doc/trpl/method-syntax.md +++ b/src/doc/trpl/method-syntax.md @@ -1,232 +0,0 @@ -% Method Syntax - -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(x))); -``` - -We would read this left-to right, and so we see "baz bar foo." But this isn't the -order that the functions would get called in, that's inside-out: "foo bar baz." -Wouldn't it be nice if we could do this instead? - -```{rust,ignore} -x.foo().bar().baz(); -``` - -Luckily, as you may have guessed with the leading question, you can! Rust provides -the ability to use this *method call syntax* via the `impl` keyword. - -## Method calls - -Here's how it works: - -```{rust} -# #![feature(core)] -struct Circle { - x: f64, - y: f64, - radius: f64, -} - -impl Circle { - fn area(&self) -> f64 { - std::f64::consts::PI * (self.radius * self.radius) - } -} - -fn main() { - let c = Circle { x: 0.0, y: 0.0, radius: 2.0 }; - println!("{}", c.area()); -} -``` - -This will print `12.566371`. - -We've made a struct that represents a circle. We then write an `impl` block, -and inside it, define a method, `area`. Methods take a special first -parameter, of which there are three variants: `self`, `&self`, and `&mut self`. -You can think of this first parameter as being the `x` in `x.foo()`. The three -variants correspond to the three kinds of thing `x` could be: `self` if it's -just a value on the stack, `&self` if it's a reference, and `&mut self` if it's -a mutable reference. We should default to using `&self`, as you should prefer -borrowing over taking ownership, as well as taking immutable references -over mutable ones. Here's an example of all three variants: - -```rust -struct Circle { - x: f64, - y: f64, - radius: f64, -} - -impl Circle { - fn reference(&self) { - println!("taking self by reference!"); - } - - fn mutable_reference(&mut self) { - println!("taking self by mutable reference!"); - } - - fn takes_ownership(self) { - println!("taking ownership of self!"); - } -} -``` - -Finally, as you may remember, the value of the area of a circle is `π*r²`. -Because we took the `&self` parameter to `area`, we can use it just like any -other parameter. Because we know it's a `Circle`, we can access the `radius` -just like we would with any other struct. An import of π and some -multiplications later, and we have our area. - -## Chaining method calls - -So, now we know how to call a method, such as `foo.bar()`. But what about our -original example, `foo.bar().baz()`? This is called 'method chaining', and we -can do it by returning `self`. - -``` -# #![feature(core)] -struct Circle { - x: f64, - y: f64, - radius: f64, -} - -impl Circle { - fn area(&self) -> f64 { - std::f64::consts::PI * (self.radius * self.radius) - } - - fn grow(&self, increment: f64) -> Circle { - Circle { x: self.x, y: self.y, radius: self.radius + increment } - } -} - -fn main() { - let c = Circle { x: 0.0, y: 0.0, radius: 2.0 }; - println!("{}", c.area()); - - let d = c.grow(2.0).area(); - println!("{}", d); -} -``` - -Check the return type: - -``` -# struct Circle; -# impl Circle { -fn grow(&self) -> Circle { -# Circle } } -``` - -We just say we're returning a `Circle`. With this method, we can grow a new -circle to any arbitrary size. - -## Static methods - -You can also define methods that do not take a `self` parameter. Here's a -pattern that's very common in Rust code: - -``` -struct Circle { - x: f64, - y: f64, - radius: f64, -} - -impl Circle { - fn new(x: f64, y: f64, radius: f64) -> Circle { - Circle { - x: x, - y: y, - radius: radius, - } - } -} - -fn main() { - let c = Circle::new(0.0, 0.0, 2.0); -} -``` - -This *static method* builds a new `Circle` for us. Note that static methods -are called with the `Struct::method()` syntax, rather than the `ref.method()` -syntax. - -## Builder Pattern - -Let's say that we want our users to be able to create Circles, but we will -allow them to only set the properties they care about. Otherwise, the `x` -and `y` attributes will be `0.0`, and the `radius` will be `1.0`. Rust doesn't -have method overloading, named arguments, or variable arguments. We employ -the builder pattern instead. It looks like this: - -``` -# #![feature(core)] -struct Circle { - x: f64, - y: f64, - radius: f64, -} - -impl Circle { - fn area(&self) -> f64 { - std::f64::consts::PI * (self.radius * self.radius) - } -} - -struct CircleBuilder { - x: f64, - y: f64, - radius: f64, -} - -impl CircleBuilder { - fn new() -> CircleBuilder { - CircleBuilder { x: 0.0, y: 0.0, radius: 0.0, } - } - - fn x(&mut self, coordinate: f64) -> &mut CircleBuilder { - self.x = coordinate; - self - } - - fn y(&mut self, coordinate: f64) -> &mut CircleBuilder { - self.y = coordinate; - self - } - - fn radius(&mut self, radius: f64) -> &mut CircleBuilder { - self.radius = radius; - self - } - - fn finalize(&self) -> Circle { - Circle { x: self.x, y: self.y, radius: self.radius } - } -} - -fn main() { - let c = CircleBuilder::new() - .x(1.0) - .y(2.0) - .radius(2.0) - .finalize(); - - println!("area: {}", c.area()); - println!("x: {}", c.x); - println!("y: {}", c.y); -} -``` - -What we've done here is make another struct, `CircleBuilder`. We've defined our -builder methods on it. We've also defined our `area()` method on `Circle`. We -also made one more method on `CircleBuilder`: `finalize()`. This method creates -our final `Circle` from the builder. Now, we've used the type system to enforce -our concerns: we can use the methods on `CircleBuilder` to constrain making -`Circle`s in any way we choose. diff --git a/src/doc/trpl/more-strings.md b/src/doc/trpl/more-strings.md deleted file mode 100644 index 17a463842e71c..0000000000000 --- a/src/doc/trpl/more-strings.md +++ /dev/null @@ -1,325 +0,0 @@ -% More Strings - -Strings are an important concept to master in any programming language. If you -come from a managed language background, you may be surprised at the complexity -of string handling in a systems programming language. Efficient access and -allocation of memory for a dynamically sized structure involves a lot of -details. Luckily, Rust has lots of tools to help us here. - -A **string** is a sequence of unicode scalar values encoded as a stream of -UTF-8 bytes. All strings are guaranteed to be validly-encoded UTF-8 sequences. -Additionally, strings are not null-terminated and can contain null bytes. - -Rust has two main types of strings: `&str` and `String`. - -# `&str` - -The first kind is a `&str`. This is pronounced a 'string slice'. -String literals are of the type `&str`: - -``` -let string = "Hello there."; -``` - -Like any Rust reference, string slices have an associated lifetime. A string -literal is a `&'static str`. A string slice can be written without an explicit -lifetime in many cases, such as in function arguments. In these cases the -lifetime will be inferred: - -``` -fn takes_slice(slice: &str) { - println!("Got: {}", slice); -} -``` - -Like vector slices, string slices are simply a pointer plus a length. This -means that they're a 'view' into an already-allocated string, such as a -string literal or a `String`. - -## `str` - -You may occasionally see references to a `str` type, without the `&`. While -this type does exist, it’s not something you want to use yourself. Sometimes, -people confuse `str` for `String`, and write this: - -```rust -struct S { - s: str, -} -``` - -This leads to ugly errors: - -```text -error: the trait `core::marker::Sized` is not implemented for the type `str` [E0277] -note: `str` does not have a constant size known at compile-time -``` - -Instead, this `struct` should be - -```rust -struct S { - s: String, -} -``` - -So let’s talk about `String`s. - -# `String` - -A `String` is a heap-allocated string. This string is growable, and is -also guaranteed to be UTF-8. `String`s are commonly created by -converting from a string slice using the `to_string` method. - -``` -let mut s = "Hello".to_string(); -println!("{}", s); - -s.push_str(", world."); -println!("{}", s); -``` - -A reference to a `String` will automatically coerce to a string slice: - -``` -fn takes_slice(slice: &str) { - println!("Got: {}", slice); -} - -fn main() { - let s = "Hello".to_string(); - takes_slice(&s); -} -``` - -You can also get a `&str` from a stack-allocated array of bytes: - -``` -use std::str; - -let x: &[u8] = &[b'a', b'b']; -let stack_str: &str = str::from_utf8(x).unwrap(); -``` - -# Best Practices - -## `String` vs. `&str` - -In general, you should prefer `String` when you need ownership, and `&str` when -you just need to borrow a string. This is very similar to using `Vec` vs. `&[T]`, -and `T` vs `&T` in general. - -This means starting off with this: - -```{rust,ignore} -fn foo(s: &str) { -``` - -and only moving to this: - -```{rust,ignore} -fn foo(s: String) { -``` - -if you have good reason. It's not polite to hold on to ownership you don't -need, and it can make your lifetimes more complex. - -## Generic functions - -To write a function that's generic over types of strings, use `&str`. - -``` -fn some_string_length(x: &str) -> usize { - x.len() -} - -fn main() { - let s = "Hello, world"; - - println!("{}", some_string_length(s)); - - let s = "Hello, world".to_string(); - - println!("{}", some_string_length(&s)); -} -``` - -Both of these lines will print `12`. - -## Indexing strings - -You may be tempted to try to access a certain character of a `String`, like -this: - -```{rust,ignore} -let s = "hello".to_string(); - -println!("{}", s[0]); -``` - -This does not compile. This is on purpose. In the world of UTF-8, direct -indexing is basically never what you want to do. The reason is that each -character can be a variable number of bytes. This means that you have to iterate -through the characters anyway, which is an O(n) operation. - -There's 3 basic levels of unicode (and its encodings): - -- code units, the underlying data type used to store everything -- code points/unicode scalar values (char) -- graphemes (visible characters) - -Rust provides iterators for each of these situations: - -- `.bytes()` will iterate over the underlying bytes -- `.chars()` will iterate over the code points -- `.graphemes()` will iterate over each grapheme - -Usually, the `graphemes()` method on `&str` is what you want: - -``` -# #![feature(unicode)] -let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé"; - -for l in s.graphemes(true) { - println!("{}", l); -} -``` - -This prints: - -```text -u͔ -n͈̰̎ -i̙̮͚̦ -c͚̉ -o̼̩̰͗ -d͔̆̓ͥ -é -``` - -Note that `l` has the type `&str` here, since a single grapheme can consist of -multiple codepoints, so a `char` wouldn't be appropriate. - -This will print out each visible character in turn, as you'd expect: first `u͔`, then -`n͈̰̎`, etc. If you wanted each individual codepoint of each grapheme, you can use `.chars()`: - -``` -let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé"; - -for l in s.chars() { - println!("{}", l); -} -``` - -This prints: - -```text -u -͔ -n -̎ -͈ -̰ -i -̙ -̮ -͚ -̦ -c -̉ -͚ -o -͗ -̼ -̩ -̰ -d -̆ -̓ -ͥ -͔ -e -́ -``` - -You can see how some of them are combining characters, and therefore the output -looks a bit odd. - -If you want the individual byte representation of each codepoint, you can use -`.bytes()`: - -``` -let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé"; - -for l in s.bytes() { - println!("{}", l); -} -``` - -This will print: - -```text -117 -205 -148 -110 -204 -142 -205 -136 -204 -176 -105 -204 -153 -204 -174 -205 -154 -204 -166 -99 -204 -137 -205 -154 -111 -205 -151 -204 -188 -204 -169 -204 -176 -100 -204 -134 -205 -131 -205 -165 -205 -148 -101 -204 -129 -``` - -Many more bytes than graphemes! - -# `Deref` coercions - -References to `String`s will automatically coerce into `&str`s. Like this: - -``` -fn hello(s: &str) { - println!("Hello, {}!", s); -} - -let slice = "Steve"; -let string = "Steve".to_string(); - -hello(slice); -hello(&string); -``` diff --git a/src/doc/trpl/move-semantics.md b/src/doc/trpl/move-semantics.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/mutability.md b/src/doc/trpl/mutability.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/unstable.md b/src/doc/trpl/nightly-rust.md similarity index 100% rename from src/doc/trpl/unstable.md rename to src/doc/trpl/nightly-rust.md diff --git a/src/doc/trpl/no-stdlib.md b/src/doc/trpl/no-stdlib.md index 094c82a08cc9d..e69de29bb2d1d 100644 --- a/src/doc/trpl/no-stdlib.md +++ b/src/doc/trpl/no-stdlib.md @@ -1,168 +0,0 @@ -% No stdlib - -By default, `std` is linked to every Rust crate. In some contexts, -this is undesirable, and can be avoided with the `#![no_std]` -attribute attached to the crate. - -```ignore -// a minimal library -#![crate_type="lib"] -#![feature(no_std)] -#![no_std] -# // fn main() {} tricked you, rustdoc! -``` - -Obviously there's more to life than just libraries: one can use -`#[no_std]` with an executable, controlling the entry point is -possible in two ways: the `#[start]` attribute, or overriding the -default shim for the C `main` function with your own. - -The function marked `#[start]` is passed the command line parameters -in the same format as C: - -``` -#![feature(lang_items, start, no_std, libc)] -#![no_std] - -// Pull in the system libc library for what crt0.o likely requires -extern crate libc; - -// Entry point for this program -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { - 0 -} - -// These functions and traits are used by the compiler, but not -// for a bare-bones hello world. These are normally -// provided by libstd. -#[lang = "stack_exhausted"] extern fn stack_exhausted() {} -#[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -# // fn main() {} tricked you, rustdoc! -``` - -To override the compiler-inserted `main` shim, one has to disable it -with `#![no_main]` and then create the appropriate symbol with the -correct ABI and the correct name, which requires overriding the -compiler's name mangling too: - -```ignore -#![feature(no_std)] -#![no_std] -#![no_main] -#![feature(lang_items, start)] - -extern crate libc; - -#[no_mangle] // ensure that this symbol is called `main` in the output -pub extern fn main(argc: i32, argv: *const *const u8) -> i32 { - 0 -} - -#[lang = "stack_exhausted"] extern fn stack_exhausted() {} -#[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -# // fn main() {} tricked you, rustdoc! -``` - - -The compiler currently makes a few assumptions about symbols which are available -in the executable to call. Normally these functions are provided by the standard -library, but without it you must define your own. - -The first of these three functions, `stack_exhausted`, is invoked whenever stack -overflow is detected. This function has a number of restrictions about how it -can be called and what it must do, but if the stack limit register is not being -maintained then a thread always has an "infinite stack" and this function -shouldn't get triggered. - -The second of these three functions, `eh_personality`, is used by the -failure mechanisms of the compiler. This is often mapped to GCC's -personality function (see the -[libstd implementation](../std/rt/unwind/index.html) for more -information), but crates which do not trigger a panic can be assured -that this function is never called. The final function, `panic_fmt`, is -also used by the failure mechanisms of the compiler. - -## Using libcore - -> **Note**: the core library's structure is unstable, and it is recommended to -> use the standard library instead wherever possible. - -With the above techniques, we've got a bare-metal executable running some Rust -code. There is a good deal of functionality provided by the standard library, -however, that is necessary to be productive in Rust. If the standard library is -not sufficient, then [libcore](../core/index.html) is designed to be used -instead. - -The core library has very few dependencies and is much more portable than the -standard library itself. Additionally, the core library has most of the -necessary functionality for writing idiomatic and effective Rust code. - -As an example, here is a program that will calculate the dot product of two -vectors provided from C, using idiomatic Rust practices. - -``` -#![feature(lang_items, start, no_std, core, libc)] -#![no_std] - -# extern crate libc; -extern crate core; - -use core::prelude::*; - -use core::mem; - -#[no_mangle] -pub extern fn dot_product(a: *const u32, a_len: u32, - b: *const u32, b_len: u32) -> u32 { - use core::raw::Slice; - - // Convert the provided arrays into Rust slices. - // The core::raw module guarantees that the Slice - // structure has the same memory layout as a &[T] - // slice. - // - // This is an unsafe operation because the compiler - // cannot tell the pointers are valid. - let (a_slice, b_slice): (&[u32], &[u32]) = unsafe { - mem::transmute(( - Slice { data: a, len: a_len as usize }, - Slice { data: b, len: b_len as usize }, - )) - }; - - // Iterate over the slices, collecting the result - let mut ret = 0; - for (i, j) in a_slice.iter().zip(b_slice.iter()) { - ret += (*i) * (*j); - } - return ret; -} - -#[lang = "panic_fmt"] -extern fn panic_fmt(args: &core::fmt::Arguments, - file: &str, - line: u32) -> ! { - loop {} -} - -#[lang = "stack_exhausted"] extern fn stack_exhausted() {} -#[lang = "eh_personality"] extern fn eh_personality() {} -# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 } -# fn main() {} -``` - -Note that there is one extra lang item here which differs from the examples -above, `panic_fmt`. This must be defined by consumers of libcore because the -core library declares panics, but it does not define it. The `panic_fmt` -lang item is this crate's definition of panic, and it must be guaranteed to -never return. - -As can be seen in this example, the core library is intended to provide the -power of Rust in all circumstances, regardless of platform requirements. Further -libraries, such as liballoc, add functionality to libcore which make other -platform-specific assumptions, but continue to be more portable than the -standard library itself. - diff --git a/src/doc/trpl/operators-and-overloading.md b/src/doc/trpl/operators-and-overloading.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index 223085cc40b8e..e69de29bb2d1d 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -1,555 +0,0 @@ -% Ownership - -This guide presents Rust's ownership system. This is one of Rust's most unique -and compelling features, with which Rust developers should become quite -acquainted. Ownership is how Rust achieves its largest goal, memory safety. -The ownership system has a few distinct concepts: *ownership*, *borrowing*, -and *lifetimes*. We'll talk about each one in turn. - -# Meta - -Before we get to the details, two important notes about the ownership system. - -Rust has a focus on safety and speed. It accomplishes these goals through many -*zero-cost abstractions*, which means that in Rust, abstractions cost as little -as possible in order to make them work. The ownership system is a prime example -of a zero cost abstraction. All of the analysis we'll talk about in this guide -is _done at compile time_. You do not pay any run-time cost for any of these -features. - -However, this system does have a certain cost: learning curve. Many new users -to Rust experience something we like to call "fighting with the borrow -checker," where the Rust compiler refuses to compile a program that the author -thinks is valid. This often happens because the programmer's mental model of -how ownership should work doesn't match the actual rules that Rust implements. -You probably will experience similar things at first. There is good news, -however: more experienced Rust developers report that once they work with the -rules of the ownership system for a period of time, they fight the borrow -checker less and less. - -With that in mind, let's learn about ownership. - -# Ownership - -At its core, ownership is about *resources*. For the purposes of the vast -majority of this guide, we will talk about a specific resource: memory. The -concept generalizes to any kind of resource, like a file handle, but to make it -more concrete, we'll focus on memory. - -When your program allocates some memory, it needs some way to deallocate that -memory. Imagine a function `foo` that allocates four bytes of memory, and then -never deallocates that memory. We call this problem *leaking* memory, because -each time we call `foo`, we're allocating another four bytes. Eventually, with -enough calls to `foo`, we will run our system out of memory. That's no good. So -we need some way for `foo` to deallocate those four bytes. It's also important -that we don't deallocate too many times, either. Without getting into the -details, attempting to deallocate memory multiple times can lead to problems. -In other words, any time some memory is allocated, we need to make sure that we -deallocate that memory once and only once. Too many times is bad, not enough -times is bad. The counts must match. - -There's one other important detail with regards to allocating memory. Whenever -we request some amount of memory, what we are given is a handle to that memory. -This handle (often called a *pointer*, when we're referring to memory) is how -we interact with the allocated memory. As long as we have that handle, we can -do something with the memory. Once we're done with the handle, we're also done -with the memory, as we can't do anything useful without a handle to it. - -Historically, systems programming languages require you to track these -allocations, deallocations, and handles yourself. For example, if we want some -memory from the heap in a language like C, we do this: - -```c -{ - int *x = malloc(sizeof(int)); - - // we can now do stuff with our handle x - *x = 5; - - free(x); -} -``` - -The call to `malloc` allocates some memory. The call to `free` deallocates the -memory. There's also bookkeeping about allocating the correct amount of memory. - -Rust combines these two aspects of allocating memory (and other resources) into -a concept called *ownership*. Whenever we request some memory, that handle we -receive is called the *owning handle*. Whenever that handle goes out of scope, -Rust knows that you cannot do anything with the memory anymore, and so -therefore deallocates the memory for you. Here's the equivalent example in -Rust: - -```rust -{ - let x = Box::new(5); -} -``` - -The `Box::new` function creates a `Box` (specifically `Box` in this -case) by allocating a small segment of memory on the heap with enough space to -fit an `i32`. But where in the code is the box deallocated? We said before that -we must have a deallocation for each allocation. Rust handles this for you. It -knows that our handle, `x`, is the owning reference to our box. Rust knows that -`x` will go out of scope at the end of the block, and so it inserts a call to -deallocate the memory at the end of the scope. Because the compiler does this -for us, it's impossible to forget. We always have exactly one deallocation - paired with each of our allocations. - -This is pretty straightforward, but what happens when we want to pass our box -to a function? Let's look at some code: - -```rust -fn main() { - let x = Box::new(5); - - add_one(x); -} - -fn add_one(mut num: Box) { - *num += 1; -} -``` - -This code works, but it's not ideal. For example, let's add one more line of -code, where we print out the value of `x`: - -```{rust,ignore} -fn main() { - let x = Box::new(5); - - add_one(x); - - println!("{}", x); -} - -fn add_one(mut num: Box) { - *num += 1; -} -``` - -This does not compile, and gives us an error: - -```text -error: use of moved value: `x` - println!("{}", x); - ^ -``` - -Remember, we need one deallocation for every allocation. When we try to pass -our box to `add_one`, we would have two handles to the memory: `x` in `main`, -and `num` in `add_one`. If we deallocated the memory when each handle went out -of scope, we would have two deallocations and one allocation, and that's wrong. -So when we call `add_one`, Rust defines `num` as the owner of the handle. And -so, now that we've given ownership to `num`, `x` is invalid. `x`'s value has -"moved" from `x` to `num`. Hence the error: use of moved value `x`. - -To fix this, we can have `add_one` give ownership back when it's done with the -box: - -```rust -fn main() { - let x = Box::new(5); - - let y = add_one(x); - - println!("{}", y); -} - -fn add_one(mut num: Box) -> Box { - *num += 1; - - num -} -``` - -This code will compile and run just fine. Now, we return a `box`, and so the -ownership is transferred back to `y` in `main`. We only have ownership for the -duration of our function before giving it back. This pattern is very common, -and so Rust introduces a concept to describe a handle which temporarily refers -to something another handle owns. It's called *borrowing*, and it's done with -*references*, designated by the `&` symbol. - -# Borrowing - -Here's the current state of our `add_one` function: - -```rust -fn add_one(mut num: Box) -> Box { - *num += 1; - - num -} -``` - -This function takes ownership, because it takes a `Box`, which owns its -contents. But then we give ownership right back. - -In the physical world, you can give one of your possessions to someone for a -short period of time. You still own your possession, you're just letting someone -else use it for a while. We call that *lending* something to someone, and that -person is said to be *borrowing* that something from you. - -Rust's ownership system also allows an owner to lend out a handle for a limited -period. This is also called *borrowing*. Here's a version of `add_one` which -borrows its argument rather than taking ownership: - -```rust -fn add_one(num: &mut i32) { - *num += 1; -} -``` - -This function borrows an `i32` from its caller, and then increments it. When -the function is over, and `num` goes out of scope, the borrow is over. - -We have to change our `main` a bit too: - -```rust -fn main() { - let mut x = 5; - - add_one(&mut x); - - println!("{}", x); -} - -fn add_one(num: &mut i32) { - *num += 1; -} -``` - -We don't need to assign the result of `add_one()` anymore, because it doesn't -return anything anymore. This is because we're not passing ownership back, -since we just borrow, not take ownership. - -# Lifetimes - -Lending out a reference to a resource that someone else owns can be -complicated, however. For example, imagine this set of operations: - -1. I acquire a handle to some kind of resource. -2. I lend you a reference to the resource. -3. I decide I'm done with the resource, and deallocate it, while you still have - your reference. -4. You decide to use the resource. - -Uh oh! Your reference is pointing to an invalid resource. This is called a -*dangling pointer* or "use after free," when the resource is memory. - -To fix this, we have to make sure that step four never happens after step -three. The ownership system in Rust does this through a concept called -*lifetimes*, which describe the scope that a reference is valid for. - -Remember the function that borrowed an `i32`? Let's look at it again. - -```rust -fn add_one(num: &mut i32) { - *num += 1; -} -``` - -Rust has a feature called *lifetime elision*, which allows you to not write -lifetime annotations in certain circumstances. This is one of them. We will -cover the others later. Without eliding the lifetimes, `add_one` looks like -this: - -```rust -fn add_one<'a>(num: &'a mut i32) { - *num += 1; -} -``` - -The `'a` is called a *lifetime*. Most lifetimes are used in places where -short names like `'a`, `'b` and `'c` are clearest, but it's often useful to -have more descriptive names. Let's dig into the syntax in a bit more detail: - -```{rust,ignore} -fn add_one<'a>(...) -``` - -This part _declares_ our lifetimes. This says that `add_one` has one lifetime, -`'a`. If we had two, it would look like this: - -```{rust,ignore} -fn add_two<'a, 'b>(...) -``` - -Then in our parameter list, we use the lifetimes we've named: - -```{rust,ignore} -...(num: &'a mut i32) -``` - -If you compare `&mut i32` to `&'a mut i32`, they're the same, it's just that the -lifetime `'a` has snuck in between the `&` and the `mut i32`. We read `&mut i32` as "a -mutable reference to an i32" and `&'a mut i32` as "a mutable reference to an i32 with the lifetime 'a.'" - -Why do lifetimes matter? Well, for example, here's some code: - -```rust -struct Foo<'a> { - x: &'a i32, -} - -fn main() { - let y = &5; // this is the same as `let _y = 5; let y = &_y;` - let f = Foo { x: y }; - - println!("{}", f.x); -} -``` - -As you can see, `struct`s can also have lifetimes. In a similar way to functions, - -```{rust} -struct Foo<'a> { -# x: &'a i32, -# } -``` - -declares a lifetime, and - -```rust -# struct Foo<'a> { -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. - -## Thinking in scopes - -A way to think about lifetimes is to visualize the scope that a reference is -valid for. For example: - -```rust -fn main() { - let y = &5; // -+ y goes into scope - // | - // stuff // | - // | -} // -+ y goes out of scope -``` - -Adding in our `Foo`: - -```rust -struct Foo<'a> { - x: &'a i32, -} - -fn main() { - let y = &5; // -+ y goes into scope - let f = Foo { x: y }; // -+ f goes into scope - // stuff // | - // | -} // -+ f and y go out of scope -``` - -Our `f` lives within the scope of `y`, so everything works. What if it didn't? -This code won't work: - -```{rust,ignore} -struct Foo<'a> { - x: &'a i32, -} - -fn main() { - let x; // -+ x goes into scope - // | - { // | - let y = &5; // ---+ y goes into scope - let f = Foo { x: y }; // ---+ f goes into scope - x = &f.x; // | | error here - } // ---+ f and y go out of scope - // | - println!("{}", x); // | -} // -+ x goes out of scope -``` - -Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope -of `x`. But when we do `x = &f.x`, we make `x` a reference to something that's -about to go out of scope. - -Named lifetimes are a way of giving these scopes a name. Giving something a -name is the first step towards being able to talk about it. - -## 'static - -The lifetime named *static* is a special lifetime. It signals that something -has the lifetime of the entire program. Most Rust programmers first come across -`'static` when dealing with strings: - -```rust -let x: &'static str = "Hello, world."; -``` - -String literals have the type `&'static str` because the reference is always -alive: they are baked into the data segment of the final binary. Another -example are globals: - -```rust -static FOO: i32 = 5; -let x: &'static i32 = &FOO; -``` - -This adds an `i32` to the data segment of the binary, and `x` is a reference -to it. - -# Shared Ownership - -In all the examples we've considered so far, we've assumed that each handle has -a singular owner. But sometimes, this doesn't work. Consider a car. Cars have -four wheels. We would want a wheel to know which car it was attached to. But -this won't work: - -```{rust,ignore} -struct Car { - name: String, -} - -struct Wheel { - size: i32, - owner: Car, -} - -fn main() { - let car = Car { name: "DeLorean".to_string() }; - - for _ in 0..4 { - Wheel { size: 360, owner: car }; - } -} -``` - -We try to make four `Wheel`s, each with a `Car` that it's attached to. But the -compiler knows that on the second iteration of the loop, there's a problem: - -```text -error: use of moved value: `car` - Wheel { size: 360, owner: car }; - ^~~ -note: `car` moved here because it has type `Car`, which is non-copyable - Wheel { size: 360, owner: car }; - ^~~ -``` - -We need our `Car` to be pointed to by multiple `Wheel`s. We can't do that with -`Box`, because it has a single owner. We can do it with `Rc` instead: - -```rust -use std::rc::Rc; - -struct Car { - name: String, -} - -struct Wheel { - size: i32, - owner: Rc, -} - -fn main() { - let car = Car { name: "DeLorean".to_string() }; - - let car_owner = Rc::new(car); - - for _ in 0..4 { - Wheel { size: 360, owner: car_owner.clone() }; - } -} -``` - -We wrap our `Car` in an `Rc`, getting an `Rc`, and then use the -`clone()` method to make new references. We've also changed our `Wheel` to have -an `Rc` rather than just a `Car`. - -This is the simplest kind of multiple ownership possible. For example, there's -also `Arc`, which uses more expensive atomic instructions to be the -thread-safe counterpart of `Rc`. - -## Lifetime Elision - -Rust supports powerful local type inference in function bodies, but it’s -forbidden in item signatures to allow reasoning about the types just based in -the item signature alone. However, for ergonomic reasons a very restricted -secondary inference algorithm called “lifetime elision” applies in function -signatures. It infers only based on the signature components themselves and not -based on the body of the function, only infers lifetime parameters, and does -this with only three easily memorizable and unambiguous rules. This makes -lifetime elision a shorthand for writing an item signature, while not hiding -away the actual types involved as full local inference would if applied to it. - -When talking about lifetime elision, we use the term *input lifetime* and -*output lifetime*. An *input lifetime* is a lifetime associated with a parameter -of a function, and an *output lifetime* is a lifetime associated with the return -value of a function. For example, this function has an input lifetime: - -```{rust,ignore} -fn foo<'a>(bar: &'a str) -``` - -This one has an output lifetime: - -```{rust,ignore} -fn foo<'a>() -> &'a str -``` - -This one has a lifetime in both positions: - -```{rust,ignore} -fn foo<'a>(bar: &'a str) -> &'a str -``` - -Here are the three rules: - -* Each elided lifetime in a function's arguments becomes a distinct lifetime - parameter. - -* If there is exactly one input lifetime, elided or not, that lifetime is - assigned to all elided lifetimes in the return values of that function. - -* If there are multiple input lifetimes, but one of them is `&self` or `&mut - self`, the lifetime of `self` is assigned to all elided output lifetimes. - -Otherwise, it is an error to elide an output lifetime. - -### Examples - -Here are some examples of functions with elided lifetimes. We've paired each -example of an elided lifetime with its expanded form. - -```{rust,ignore} -fn print(s: &str); // elided -fn print<'a>(s: &'a str); // expanded - -fn debug(lvl: u32, s: &str); // elided -fn debug<'a>(lvl: u32, s: &'a str); // expanded - -// In the preceding example, `lvl` doesn't need a lifetime because it's not a -// reference (`&`). Only things relating to references (such as a `struct` -// which contains a reference) need lifetimes. - -fn substr(s: &str, until: u32) -> &str; // elided -fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded - -fn get_str() -> &str; // ILLEGAL, no inputs - -fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs -fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is unclear - -fn get_mut(&mut self) -> &mut T; // elided -fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded - -fn args(&mut self, args: &[T]) -> &mut Command // elided -fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded - -fn new(buf: &mut [u8]) -> BufWriter; // elided -fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded -``` - -# Related Resources - -Coming Soon. diff --git a/src/doc/trpl/patterns.md b/src/doc/trpl/patterns.md index 4ebf696aa57a0..e69de29bb2d1d 100644 --- a/src/doc/trpl/patterns.md +++ b/src/doc/trpl/patterns.md @@ -1,200 +0,0 @@ -% Patterns - -We've made use of patterns a few times in the guide: first with `let` bindings, -then with `match` statements. Let's go on a whirlwind tour of all of the things -patterns can do! - -A quick refresher: you can match against literals directly, and `_` acts as an -*any* case: - -```{rust} -let x = 1; - -match x { - 1 => println!("one"), - 2 => println!("two"), - 3 => println!("three"), - _ => println!("anything"), -} -``` - -You can match multiple patterns with `|`: - -```{rust} -let x = 1; - -match x { - 1 | 2 => println!("one or two"), - 3 => println!("three"), - _ => println!("anything"), -} -``` - -You can match a range of values with `...`: - -```{rust} -let x = 1; - -match x { - 1 ... 5 => println!("one through five"), - _ => println!("anything"), -} -``` - -Ranges are mostly used with integers and single characters. - -If you're matching multiple things, via a `|` or a `...`, you can bind -the value to a name with `@`: - -```{rust} -let x = 1; - -match x { - e @ 1 ... 5 => println!("got a range element {}", e), - _ => println!("anything"), -} -``` - -If you're matching on an enum which has variants, you can use `..` to -ignore the value and type in the variant: - -```{rust} -enum OptionalInt { - Value(i32), - Missing, -} - -let x = OptionalInt::Value(5); - -match x { - OptionalInt::Value(..) => println!("Got an int!"), - OptionalInt::Missing => println!("No such luck."), -} -``` - -You can introduce *match guards* with `if`: - -```{rust} -enum OptionalInt { - Value(i32), - Missing, -} - -let x = OptionalInt::Value(5); - -match x { - OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"), - OptionalInt::Value(..) => println!("Got an int!"), - OptionalInt::Missing => println!("No such luck."), -} -``` - -If you're matching on a pointer, you can use the same syntax as you declared it -with. First, `&`: - -```{rust} -let x = &5; - -match x { - &val => println!("Got a value: {}", val), -} -``` - -Here, the `val` inside the `match` has type `i32`. In other words, the left-hand -side of the pattern destructures the value. If we have `&5`, then in `&val`, `val` -would be `5`. - -If you want to get a reference, use the `ref` keyword: - -```{rust} -let x = 5; - -match x { - ref r => println!("Got a reference to {}", r), -} -``` - -Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref` -keyword _creates_ a reference, for use in the pattern. If you need a mutable -reference, `ref mut` will work in the same way: - -```{rust} -let mut x = 5; - -match x { - ref mut mr => println!("Got a mutable reference to {}", mr), -} -``` - -If you have a struct, you can destructure it inside of a pattern: - -```{rust} -# #![allow(non_shorthand_field_patterns)] -struct Point { - x: i32, - y: i32, -} - -let origin = Point { x: 0, y: 0 }; - -match origin { - Point { x: x, y: y } => println!("({},{})", x, y), -} -``` - -If we only care about some of the values, we don't have to give them all names: - -```{rust} -# #![allow(non_shorthand_field_patterns)] -struct Point { - x: i32, - y: i32, -} - -let origin = Point { x: 0, y: 0 }; - -match origin { - Point { x: x, .. } => println!("x is {}", x), -} -``` - -You can do this kind of match on any member, not just the first: - -```{rust} -# #![allow(non_shorthand_field_patterns)] -struct Point { - x: i32, - y: i32, -} - -let origin = Point { x: 0, y: 0 }; - -match origin { - Point { y: y, .. } => println!("y is {}", y), -} -``` - -If you want to match against a slice or array, you can use `&`: - -```{rust} -# #![feature(slice_patterns)] -fn main() { - let v = vec!["match_this", "1"]; - - match &v[..] { - ["match_this", second] => println!("The second element is {}", second), - _ => {}, - } -} -``` - -Whew! That's a lot of different ways to match things, and they can all be -mixed and matched, depending on what you're doing: - -```{rust,ignore} -match x { - Foo { x: Some(ref name), y: None } => ... -} -``` - -Patterns are very powerful. Make good use of them. diff --git a/src/doc/trpl/plugins.md b/src/doc/trpl/plugins.md index 9eb22a7f6985a..e69de29bb2d1d 100644 --- a/src/doc/trpl/plugins.md +++ b/src/doc/trpl/plugins.md @@ -1,242 +0,0 @@ -% Compiler Plugins - -# Introduction - -`rustc` can load compiler plugins, which are user-provided libraries that -extend the compiler's behavior with new syntax extensions, lint checks, etc. - -A plugin is a dynamic library crate with a designated *registrar* function that -registers extensions with `rustc`. Other crates can load these extensions using -the crate attribute `#![plugin(...)]`. See the -[`rustc::plugin`](../rustc/plugin/index.html) documentation for more about the -mechanics of defining and loading a plugin. - -If present, arguments passed as `#![plugin(foo(... args ...))]` are not -interpreted by rustc itself. They are provided to the plugin through the -`Registry`'s [`args` method](../rustc/plugin/registry/struct.Registry.html#method.args). - -In the vast majority of cases, a plugin should *only* be used through -`#![plugin]` and not through an `extern crate` item. Linking a plugin would -pull in all of libsyntax and librustc as dependencies of your crate. This is -generally unwanted unless you are building another plugin. The -`plugin_as_library` lint checks these guidelines. - -The usual practice is to put compiler plugins in their own crate, separate from -any `macro_rules!` macros or ordinary Rust code meant to be used by consumers -of a library. - -# Syntax extensions - -Plugins can extend Rust's syntax in various ways. One kind of syntax extension -is the procedural macro. These are invoked the same way as [ordinary -macros](macros.html), but the expansion is performed by arbitrary Rust -code that manipulates [syntax trees](../syntax/ast/index.html) at -compile time. - -Let's write a plugin -[`roman_numerals.rs`](https://github.com/rust-lang/rust/tree/master/src/test/auxiliary/roman_numerals.rs) -that implements Roman numeral integer literals. - -```ignore -#![crate_type="dylib"] -#![feature(plugin_registrar, rustc_private)] - -extern crate syntax; -extern crate rustc; - -use syntax::codemap::Span; -use syntax::parse::token; -use syntax::ast::{TokenTree, TtToken}; -use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; -use syntax::ext::build::AstBuilder; // trait for expr_usize -use rustc::plugin::Registry; - -fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) - -> Box { - - static NUMERALS: &'static [(&'static str, u32)] = &[ - ("M", 1000), ("CM", 900), ("D", 500), ("CD", 400), - ("C", 100), ("XC", 90), ("L", 50), ("XL", 40), - ("X", 10), ("IX", 9), ("V", 5), ("IV", 4), - ("I", 1)]; - - let text = match args { - [TtToken(_, token::Ident(s, _))] => token::get_ident(s).to_string(), - _ => { - cx.span_err(sp, "argument should be a single identifier"); - return DummyResult::any(sp); - } - }; - - let mut text = &*text; - let mut total = 0; - while !text.is_empty() { - match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) { - Some(&(rn, val)) => { - total += val; - text = &text[rn.len()..]; - } - None => { - cx.span_err(sp, "invalid Roman numeral"); - return DummyResult::any(sp); - } - } - } - - MacEager::expr(cx.expr_u32(sp, total)) -} - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_macro("rn", expand_rn); -} -``` - -Then we can use `rn!()` like any other macro: - -```ignore -#![feature(plugin)] -#![plugin(roman_numerals)] - -fn main() { - assert_eq!(rn!(MMXV), 2015); -} -``` - -The advantages over a simple `fn(&str) -> u32` are: - -* The (arbitrarily complex) conversion is done at compile time. -* Input validation is also performed at compile time. -* It can be extended to allow use in patterns, which effectively gives - a way to define new literal syntax for any data type. - -In addition to procedural macros, you can define new -[`derive`](../reference.html#derive)-like attributes and other kinds of -extensions. See -[`Registry::register_syntax_extension`](../rustc/plugin/registry/struct.Registry.html#method.register_syntax_extension) -and the [`SyntaxExtension` -enum](http://doc.rust-lang.org/syntax/ext/base/enum.SyntaxExtension.html). For -a more involved macro example, see -[`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs). - - -## Tips and tricks - -Some of the [macro debugging tips](macros.html#debugging-macro-code) are applicable. - -You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into -higher-level syntax elements like expressions: - -```ignore -fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) - -> Box { - - let mut parser = cx.new_parser_from_tts(args); - - let expr: P = parser.parse_expr(); -``` - -Looking through [`libsyntax` parser -code](https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs) -will give you a feel for how the parsing infrastructure works. - -Keep the [`Span`s](../syntax/codemap/struct.Span.html) of -everything you parse, for better error reporting. You can wrap -[`Spanned`](../syntax/codemap/struct.Spanned.html) around -your custom data structures. - -Calling -[`ExtCtxt::span_fatal`](../syntax/ext/base/struct.ExtCtxt.html#method.span_fatal) -will immediately abort compilation. It's better to instead call -[`ExtCtxt::span_err`](../syntax/ext/base/struct.ExtCtxt.html#method.span_err) -and return -[`DummyResult`](../syntax/ext/base/struct.DummyResult.html), -so that the compiler can continue and find further errors. - -To print syntax fragments for debugging, you can use -[`span_note`](../syntax/ext/base/struct.ExtCtxt.html#method.span_note) together -with -[`syntax::print::pprust::*_to_string`](http://doc.rust-lang.org/syntax/print/pprust/index.html#functions). - -The example above produced an integer literal using -[`AstBuilder::expr_usize`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_usize). -As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of -[quasiquote macros](../syntax/ext/quote/index.html). They are undocumented and -very rough around the edges. However, the implementation may be a good -starting point for an improved quasiquote as an ordinary plugin library. - - -# Lint plugins - -Plugins can extend [Rust's lint -infrastructure](../reference.html#lint-check-attributes) with additional checks for -code style, safety, etc. You can see -[`src/test/auxiliary/lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs) -for a full example, the core of which is reproduced here: - -```ignore -declare_lint!(TEST_LINT, Warn, - "Warn about items named 'lintme'") - -struct Pass; - -impl LintPass for Pass { - fn get_lints(&self) -> LintArray { - lint_array!(TEST_LINT) - } - - fn check_item(&mut self, cx: &Context, it: &ast::Item) { - let name = token::get_ident(it.ident); - if name.get() == "lintme" { - cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"); - } - } -} - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_lint_pass(box Pass as LintPassObject); -} -``` - -Then code like - -```ignore -#![plugin(lint_plugin_test)] - -fn lintme() { } -``` - -will produce a compiler warning: - -```txt -foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default -foo.rs:4 fn lintme() { } - ^~~~~~~~~~~~~~~ -``` - -The components of a lint plugin are: - -* one or more `declare_lint!` invocations, which define static - [`Lint`](../rustc/lint/struct.Lint.html) structs; - -* a struct holding any state needed by the lint pass (here, none); - -* a [`LintPass`](../rustc/lint/trait.LintPass.html) - implementation defining how to check each syntax element. A single - `LintPass` may call `span_lint` for several different `Lint`s, but should - register them all through the `get_lints` method. - -Lint passes are syntax traversals, but they run at a late stage of compilation -where type information is available. `rustc`'s [built-in -lints](https://github.com/rust-lang/rust/blob/master/src/librustc/lint/builtin.rs) -mostly use the same infrastructure as lint plugins, and provide examples of how -to access type information. - -Lints defined by plugins are controlled by the usual [attributes and compiler -flags](../reference.html#lint-check-attributes), e.g. `#[allow(test_lint)]` or -`-A test-lint`. These identifiers are derived from the first argument to -`declare_lint!`, with appropriate case and punctuation conversion. - -You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`, -including those provided by plugins loaded by `foo.rs`. diff --git a/src/doc/trpl/pointers.md b/src/doc/trpl/pointers.md deleted file mode 100644 index 1b3f2a5b7734c..0000000000000 --- a/src/doc/trpl/pointers.md +++ /dev/null @@ -1,699 +0,0 @@ -% Pointers - -Rust's pointers are one of its more unique and compelling features. Pointers -are also one of the more confusing topics for newcomers to Rust. They can also -be confusing for people coming from other languages that support pointers, such -as C++. This guide will help you understand this important topic. - -Be sceptical of non-reference pointers in Rust: use them for a deliberate -purpose, not just to make the compiler happy. Each pointer type comes with an -explanation about when they are appropriate to use. Default to references -unless you're in one of those specific situations. - -You may be interested in the [cheat sheet](#cheat-sheet), which gives a quick -overview of the types, names, and purpose of the various pointers. - -# An introduction - -If you aren't familiar with the concept of pointers, here's a short -introduction. Pointers are a very fundamental concept in systems programming -languages, so it's important to understand them. - -## Pointer Basics - -When you create a new variable binding, you're giving a name to a value that's -stored at a particular location on the stack. (If you're not familiar with the -*heap* vs. *stack*, please check out [this Stack Overflow -question](http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap), -as the rest of this guide assumes you know the difference.) Like this: - -```{rust} -let x = 5; -let y = 8; -``` - -| location | value | -|----------|-------| -| 0xd3e030 | 5 | -| 0xd3e028 | 8 | - -We're making up memory locations here, they're just sample values. Anyway, the -point is that `x`, the name we're using for our variable, corresponds to the -memory location `0xd3e030`, and the value at that location is `5`. When we -refer to `x`, we get the corresponding value. Hence, `x` is `5`. - -Let's introduce a pointer. In some languages, there is just one type of -'pointer,' but in Rust, we have many types. In this case, we'll use a Rust -*reference*, which is the simplest kind of pointer. - -```{rust} -let x = 5; -let y = 8; -let z = &y; -``` - -|location | value | -|-------- |----------| -|0xd3e030 | 5 | -|0xd3e028 | 8 | -|0xd3e020 | 0xd3e028 | - -See the difference? Rather than contain a value, the value of a pointer is a -location in memory. In this case, the location of `y`. `x` and `y` have the -type `i32`, but `z` has the type `&i32`. We can print this location using the -`{:p}` format string: - -```{rust} -let x = 5; -let y = 8; -let z = &y; - -println!("{:p}", z); -``` - -This would print `0xd3e028`, with our fictional memory addresses. - -Because `i32` and `&i32` are different types, we can't, for example, add them -together: - -```{rust,ignore} -let x = 5; -let y = 8; -let z = &y; - -println!("{}", x + z); -``` - -This gives us an error: - -```text -hello.rs:6:24: 6:25 error: mismatched types: expected `_`, found `&_` (expected integral variable, found &-ptr) -hello.rs:6 println!("{}", x + z); - ^ -``` - -We can *dereference* the pointer by using the `*` operator. Dereferencing a -pointer means accessing the value at the location stored in the pointer. This -will work: - -```{rust} -let x = 5; -let y = 8; -let z = &y; - -println!("{}", x + *z); -``` - -It prints `13`. - -That's it! That's all pointers are: they point to some memory location. Not -much else to them. Now that we've discussed the *what* of pointers, let's -talk about the *why*. - -## Pointer uses - -Rust's pointers are quite useful, but in different ways than in other systems -languages. We'll talk about best practices for Rust pointers later in -the guide, but here are some ways that pointers are useful in other languages: - -In C, strings are a pointer to a list of `char`s, ending with a null byte. -The only way to use strings is to get quite familiar with pointers. - -Pointers are useful to point to memory locations that are not on the stack. For -example, our example used two stack variables, so we were able to give them -names. But if we allocated some heap memory, we wouldn't have that name -available. In C, `malloc` is used to allocate heap memory, and it returns a -pointer. - -As a more general variant of the previous two points, any time you have a -structure that can change in size, you need a pointer. You can't tell at -compile time how much memory to allocate, so you've gotta use a pointer to -point at the memory where it will be allocated, and deal with it at run time. - -Pointers are useful in languages that are pass-by-value, rather than -pass-by-reference. Basically, languages can make two choices (this is made -up syntax, it's not Rust): - -```text -func foo(x) { - x = 5 -} - -func main() { - i = 1 - foo(i) - // what is the value of i here? -} -``` - -In languages that are pass-by-value, `foo` will get a copy of `i`, and so -the original version of `i` is not modified. At the comment, `i` will still be -`1`. In a language that is pass-by-reference, `foo` will get a reference to `i`, -and therefore, can change its value. At the comment, `i` will be `5`. - -So what do pointers have to do with this? Well, since pointers point to a -location in memory... - -```text -func foo(&i32 x) { - *x = 5 -} - -func main() { - i = 1 - foo(&i) - // what is the value of i here? -} -``` - -Even in a language which is pass by value, `i` will be `5` at the comment. You -see, because the argument `x` is a pointer, we do send a copy over to `foo`, -but because it points at a memory location, which we then assign to, the -original value is still changed. This pattern is called -*pass-reference-by-value*. Tricky! - -## Common pointer problems - -We've talked about pointers, and we've sung their praises. So what's the -downside? Well, Rust attempts to mitigate each of these kinds of problems, -but here are problems with pointers in other languages: - -Uninitialized pointers can cause a problem. For example, what does this program -do? - -```{ignore} -&int x; -*x = 5; // whoops! -``` - -Who knows? We just declare a pointer, but don't point it at anything, and then -set the memory location that it points at to be `5`. But which location? Nobody -knows. This might be harmless, and it might be catastrophic. - -When you combine pointers and functions, it's easy to accidentally invalidate -the memory the pointer is pointing to. For example: - -```text -func make_pointer(): &int { - x = 5; - - return &x; -} - -func main() { - &int i = make_pointer(); - *i = 5; // uh oh! -} -``` - -`x` is local to the `make_pointer` function, and therefore, is invalid as soon -as `make_pointer` returns. But we return a pointer to its memory location, and -so back in `main`, we try to use that pointer, and it's a very similar -situation to our first one. Setting invalid memory locations is bad. - -As one last example of a big problem with pointers, *aliasing* can be an -issue. Two pointers are said to alias when they point at the same location -in memory. Like this: - -```text -func mutate(&int i, int j) { - *i = j; -} - -func main() { - x = 5; - y = &x; - z = &x; //y and z are aliased - - - run_in_new_thread(mutate, y, 1); - run_in_new_thread(mutate, z, 100); - - // what is the value of x here? -} -``` - -In this made-up example, `run_in_new_thread` spins up a new thread, and calls -the given function name with its arguments. Since we have two threads, and -they're both operating on aliases to `x`, we can't tell which one finishes -first, and therefore, the value of `x` is actually non-deterministic. Worse, -what if one of them had invalidated the memory location they pointed to? We'd -have the same problem as before, where we'd be setting an invalid location. - -## Conclusion - -That's a basic overview of pointers as a general concept. As we alluded to -before, Rust has different kinds of pointers, rather than just one, and -mitigates all of the problems that we talked about, too. This does mean that -Rust pointers are slightly more complicated than in other languages, but -it's worth it to not have the problems that simple pointers have. - -# References - -The most basic type of pointer that Rust has is called a *reference*. Rust -references look like this: - -```{rust} -let x = 5; -let y = &x; - -println!("{}", *y); -println!("{:p}", y); -println!("{}", y); -``` - -We'd say "`y` is a reference to `x`." The first `println!` prints out the -value of `y`'s referent by using the dereference operator, `*`. The second -one prints out the memory location that `y` points to, by using the pointer -format string. The third `println!` *also* prints out the value of `y`'s -referent, because `println!` will automatically dereference it for us. - -Here's a function that takes a reference: - -```{rust} -fn succ(x: &i32) -> i32 { *x + 1 } -``` - -You can also use `&` as an operator to create a reference, so we can -call this function in two different ways: - -```{rust} -fn succ(x: &i32) -> i32 { *x + 1 } - -fn main() { - - let x = 5; - let y = &x; - - println!("{}", succ(y)); - println!("{}", succ(&x)); -} -``` - -Both of these `println!`s will print out `6`. - -Of course, if this were real code, we wouldn't bother with the reference, and -just write: - -```{rust} -fn succ(x: i32) -> i32 { x + 1 } -``` - -References are immutable by default: - -```{rust,ignore} -let x = 5; -let y = &x; - -*y = 5; // error: cannot assign to immutable borrowed content `*y` -``` - -They can be made mutable with `mut`, but only if its referent is also mutable. -This works: - -```{rust} -let mut x = 5; -let y = &mut x; -``` - -This does not: - -```{rust,ignore} -let x = 5; -let y = &mut x; // error: cannot borrow immutable local variable `x` as mutable -``` - -Immutable pointers are allowed to alias: - -```{rust} -let x = 5; -let y = &x; -let z = &x; -``` - -Mutable ones, however, are not: - -```{rust,ignore} -let mut x = 5; -let y = &mut x; -let z = &mut x; // error: cannot borrow `x` as mutable more than once at a time -``` - -Despite their complete safety, a reference's representation at runtime is the -same as that of an ordinary pointer in a C program. They introduce zero -overhead. The compiler does all safety checks at compile time. The theory that -allows for this was originally called *region pointers*. Region pointers -evolved into what we know today as *lifetimes*. - -Here's the simple explanation: would you expect this code to compile? - -```{rust,ignore} -fn main() { - println!("{}", x); - let x = 5; -} -``` - -Probably not. That's because you know that the name `x` is valid from where -it's declared to when it goes out of scope. In this case, that's the end of -the `main` function. So you know this code will cause an error. We call this -duration a *lifetime*. Let's try a more complex example: - -```{rust} -fn main() { - let mut x = 5; - - if x < 10 { - let y = &x; - - println!("Oh no: {}", y); - return; - } - - x -= 1; - - println!("Oh no: {}", x); -} -``` - -Here, we're borrowing a pointer to `x` inside of the `if`. The compiler, however, -is able to determine that that pointer will go out of scope without `x` being -mutated, and therefore, lets us pass. This wouldn't work: - -```{rust,ignore} -fn main() { - let mut x = 5; - - if x < 10 { - let y = &x; - - x -= 1; - - println!("Oh no: {}", y); - return; - } - - x -= 1; - - println!("Oh no: {}", x); -} -``` - -It gives this error: - -```text -test.rs:7:9: 7:15 error: cannot assign to `x` because it is borrowed -test.rs:7 x -= 1; - ^~~~~~ -test.rs:5:18: 5:19 note: borrow of `x` occurs here -test.rs:5 let y = &x; - ^ -``` - -As you might guess, this kind of analysis is complex for a human, and therefore -hard for a computer, too! There is an entire [guide devoted to references, ownership, -and lifetimes](ownership.html) that goes into this topic in -great detail, so if you want the full details, check that out. - -## Best practices - -In general, prefer stack allocation over heap allocation. Using references to -stack allocated information is preferred whenever possible. Therefore, -references are the default pointer type you should use, unless you have a -specific reason to use a different type. The other types of pointers cover when -they're appropriate to use in their own best practices sections. - -Use references when you want to use a pointer, but do not want to take ownership. -References just borrow ownership, which is more polite if you don't need the -ownership. In other words, prefer: - -```{rust} -fn succ(x: &i32) -> i32 { *x + 1 } -``` - -to - -```{rust} -fn succ(x: Box) -> i32 { *x + 1 } -``` - -As a corollary to that rule, references allow you to accept a wide variety of -other pointers, and so are useful so that you don't have to write a number -of variants per pointer. In other words, prefer: - -```{rust} -fn succ(x: &i32) -> i32 { *x + 1 } -``` - -to - -```{rust} -use std::rc::Rc; - -fn box_succ(x: Box) -> i32 { *x + 1 } - -fn rc_succ(x: Rc) -> i32 { *x + 1 } -``` - -Note that the caller of your function will have to modify their calls slightly: - -```{rust} -use std::rc::Rc; - -fn succ(x: &i32) -> i32 { *x + 1 } - -let ref_x = &5; -let box_x = Box::new(5); -let rc_x = Rc::new(5); - -succ(ref_x); -succ(&*box_x); -succ(&*rc_x); -``` - -The initial `*` dereferences the pointer, and then `&` takes a reference to -those contents. - -# Boxes - -`Box` is Rust's *boxed pointer* type. Boxes provide the simplest form of -heap allocation in Rust. Creating a box looks like this: - -```{rust} -let x = Box::new(5); -``` - -Boxes are heap allocated and they are deallocated automatically by Rust when -they go out of scope: - -```{rust} -{ - let x = Box::new(5); - - // stuff happens - -} // x is destructed and its memory is free'd here -``` - -However, boxes do _not_ use reference counting or garbage collection. Boxes are -what's called an *affine type*. This means that the Rust compiler, at compile -time, determines when the box comes into and goes out of scope, and inserts the -appropriate calls there. - -You don't need to fully grok the theory of affine types to grok boxes, though. -As a rough approximation, you can treat this Rust code: - -```{rust} -{ - let x = Box::new(5); - - // stuff happens -} -``` - -As being similar to this C code: - -```c -{ - int *x; - x = (int *)malloc(sizeof(int)); - *x = 5; - - // stuff happens - - free(x); -} -``` - -Of course, this is a 10,000 foot view. It leaves out destructors, for example. -But the general idea is correct: you get the semantics of `malloc`/`free`, but -with some improvements: - -1. It's impossible to allocate the incorrect amount of memory, because Rust - figures it out from the types. -2. You cannot forget to `free` memory you've allocated, because Rust does it - for you. -3. Rust ensures that this `free` happens at the right time, when it is truly - not used. Use-after-free is not possible. -4. Rust enforces that no other writeable pointers alias to this heap memory, - which means writing to an invalid pointer is not possible. - -See the section on references or the [ownership guide](ownership.html) -for more detail on how lifetimes work. - -Using boxes and references together is very common. For example: - -```{rust} -fn add_one(x: &i32) -> i32 { - *x + 1 -} - -fn main() { - let x = Box::new(5); - - println!("{}", add_one(&*x)); -} -``` - -In this case, Rust knows that `x` is being *borrowed* by the `add_one()` -function, and since it's only reading the value, allows it. - -We can borrow `x` as read-only multiple times, even simultaneously: - -```{rust} -fn add(x: &i32, y: &i32) -> i32 { - *x + *y -} - -fn main() { - let x = Box::new(5); - - println!("{}", add(&*x, &*x)); - println!("{}", add(&*x, &*x)); -} -``` - -We can mutably borrow `x` multiple times, but only if x itself is mutable, and -it may not be *simultaneously* borrowed: - -```{rust,ignore} -fn increment(x: &mut i32) { - *x += 1; -} - -fn main() { - // If variable x is not "mut", this will not compile - let mut x = Box::new(5); - - increment(&mut x); - increment(&mut x); - println!("{}", x); -} -``` - -Notice the signature of `increment()` requests a mutable reference. - -## Best practices - -Boxes are most appropriate to use when defining recursive data structures. - -### Recursive data structures - -Sometimes, you need a recursive data structure. The simplest is known as a -*cons list*: - - -```{rust} -#[derive(Debug)] -enum List { - Cons(T, Box>), - Nil, -} - -fn main() { - let list: List = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Cons(3, Box::new(List::Nil)))))); - println!("{:?}", list); -} -``` - -This prints: - -```text -Cons(1, Box(Cons(2, Box(Cons(3, Box(Nil)))))) -``` - -The reference to another `List` inside of the `Cons` enum variant must be a box, -because we don't know the length of the list. Because we don't know the length, -we don't know the size, and therefore, we need to heap allocate our list. - -Working with recursive or other unknown-sized data structures is the primary -use-case for boxes. - -# Rc and Arc - -This part is coming soon. - -## Best practices - -This part is coming soon. - -# Raw Pointers - -This part is coming soon. - -## Best practices - -This part is coming soon. - -# Creating your own Pointers - -This part is coming soon. - -## Best practices - -This part is coming soon. - -# Patterns and `ref` - -When you're trying to match something that's stored in a pointer, there may be -a situation where matching directly isn't the best option available. Let's see -how to properly handle this: - -```{rust,ignore} -fn possibly_print(x: &Option) { - match *x { - // BAD: cannot move out of a `&` - Some(s) => println!("{}", s) - - // GOOD: instead take a reference into the memory of the `Option` - Some(ref s) => println!("{}", *s), - None => {} - } -} -``` - -The `ref s` here means that `s` will be of type `&String`, rather than type -`String`. - -This is important when the type you're trying to get access to has a destructor -and you don't want to move it, you just want a reference to it. - -# Cheat Sheet - -Here's a quick rundown of Rust's pointer types: - -| Type | Name | Summary | -|--------------|---------------------|---------------------------------------------------------------------| -| `&T` | Reference | Allows one or more references to read `T` | -| `&mut T` | Mutable Reference | Allows a single reference to read and write `T` | -| `Box` | Box | Heap allocated `T` with a single owner that may read and write `T`. | -| `Rc` | "arr cee" pointer | Heap allocated `T` with many readers | -| `Arc` | Arc pointer | Same as above, but safe sharing across threads | -| `*const T` | Raw pointer | Unsafe read access to `T` | -| `*mut T` | Mutable raw pointer | Unsafe read and write access to `T` | - -# Related resources - -* [API documentation for Box](../std/boxed/index.html) -* [Ownership guide](ownership.html) -* [Cyclone paper on regions](http://www.cs.umd.edu/projects/cyclone/papers/cyclone-regions.pdf), which inspired Rust's lifetime system diff --git a/src/doc/trpl/primitive-types.md b/src/doc/trpl/primitive-types.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/references-and-borrowing.md b/src/doc/trpl/references-and-borrowing.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/slices.md b/src/doc/trpl/slices.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/static-and-dynamic-dispatch.md b/src/doc/trpl/static-and-dynamic-dispatch.md deleted file mode 100644 index a7794814156e6..0000000000000 --- a/src/doc/trpl/static-and-dynamic-dispatch.md +++ /dev/null @@ -1,306 +0,0 @@ -% Static and Dynamic Dispatch - -When code involves polymorphism, there needs to be a mechanism to determine -which specific version is actually run. This is called 'dispatch.' There are -two major forms of dispatch: static dispatch and dynamic dispatch. While Rust -favors static dispatch, it also supports dynamic dispatch through a mechanism -called 'trait objects.' - -## Background - -For the rest of this chapter, we'll need a trait and some implementations. -Let's make a simple one, `Foo`. It has one method that is expected to return a -`String`. - -```rust -trait Foo { - fn method(&self) -> String; -} -``` - -We'll also implement this trait for `u8` and `String`: - -```rust -# trait Foo { fn method(&self) -> String; } -impl Foo for u8 { - fn method(&self) -> String { format!("u8: {}", *self) } -} - -impl Foo for String { - fn method(&self) -> String { format!("string: {}", *self) } -} -``` - - -## Static dispatch - -We can use this trait to perform static dispatch with trait bounds: - -```rust -# trait Foo { fn method(&self) -> String; } -# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } } -# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } } -fn do_something(x: T) { - x.method(); -} - -fn main() { - let x = 5u8; - let y = "Hello".to_string(); - - do_something(x); - do_something(y); -} -``` - -Rust uses 'monomorphization' to perform static dispatch here. This means that -Rust will create a special version of `do_something()` for both `u8` and -`String`, and then replace the call sites with calls to these specialized -functions. In other words, Rust generates something like this: - -```rust -# trait Foo { fn method(&self) -> String; } -# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } } -# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } } -fn do_something_u8(x: u8) { - x.method(); -} - -fn do_something_string(x: String) { - x.method(); -} - -fn main() { - let x = 5u8; - let y = "Hello".to_string(); - - do_something_u8(x); - do_something_string(y); -} -``` - -This has a great upside: static dispatch allows function calls to be -inlined because the callee is known at compile time, and inlining is -the key to good optimization. Static dispatch is fast, but it comes at -a tradeoff: 'code bloat', due to many copies of the same function -existing in the binary, one for each type. - -Furthermore, compilers aren’t perfect and may “optimize” code to become slower. -For example, functions inlined too eagerly will bloat the instruction cache -(cache rules everything around us). This is part of the reason that `#[inline]` -and `#[inline(always)]` should be used carefully, and one reason why using a -dynamic dispatch is sometimes more efficient. - -However, the common case is that it is more efficient to use static dispatch, -and one can always have a thin statically-dispatched wrapper function that does -a dynamic dispatch, but not vice versa, meaning static calls are more flexible. -The standard library tries to be statically dispatched where possible for this -reason. - -## Dynamic dispatch - -Rust provides dynamic dispatch through a feature called 'trait objects.' Trait -objects, like `&Foo` or `Box`, are normal values that store a value of -*any* type that implements the given trait, where the precise type can only be -known at runtime. - -A trait object can be obtained from a pointer to a concrete type that -implements the trait by *casting* it (e.g. `&x as &Foo`) or *coercing* it -(e.g. using `&x` as an argument to a function that takes `&Foo`). - -These trait object coercions and casts also work for pointers like `&mut T` to -`&mut Foo` and `Box` to `Box`, but that's all at the moment. Coercions -and casts are identical. - -This operation can be seen as "erasing" the compiler's knowledge about the -specific type of the pointer, and hence trait objects are sometimes referred to -as "type erasure". - -Coming back to the example above, we can use the same trait to perform dynamic -dispatch with trait objects by casting: - -```rust -# trait Foo { fn method(&self) -> String; } -# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } } -# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } } - -fn do_something(x: &Foo) { - x.method(); -} - -fn main() { - let x = 5u8; - do_something(&x as &Foo); -} -``` - -or by coercing: - -```rust -# trait Foo { fn method(&self) -> String; } -# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } } -# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } } - -fn do_something(x: &Foo) { - x.method(); -} - -fn main() { - let x = "Hello".to_string(); - do_something(&x); -} -``` - -A function that takes a trait object is not specialized to each of the types -that implements `Foo`: only one copy is generated, often (but not always) -resulting in less code bloat. However, this comes at the cost of requiring -slower virtual function calls, and effectively inhibiting any chance of -inlining and related optimisations from occurring. - -### Why pointers? - -Rust does not put things behind a pointer by default, unlike many managed -languages, so types can have different sizes. Knowing the size of the value at -compile time is important for things like passing it as an argument to a -function, moving it about on the stack and allocating (and deallocating) space -on the heap to store it. - -For `Foo`, we would need to have a value that could be at least either a -`String` (24 bytes) or a `u8` (1 byte), as well as any other type for which -dependent crates may implement `Foo` (any number of bytes at all). There's no -way to guarantee that this last point can work if the values are stored without -a pointer, because those other types can be arbitrarily large. - -Putting the value behind a pointer means the size of the value is not relevant -when we are tossing a trait object around, only the size of the pointer itself. - -### Representation - -The methods of the trait can be called on a trait object via a special record -of function pointers traditionally called a 'vtable' (created and managed by -the compiler). - -Trait objects are both simple and complicated: their core representation and -layout is quite straight-forward, but there are some curly error messages and -surprising behaviors to discover. - -Let's start simple, with the runtime representation of a trait object. The -`std::raw` module contains structs with layouts that are the same as the -complicated built-in types, [including trait objects][stdraw]: - -```rust -# mod foo { -pub struct TraitObject { - pub data: *mut (), - pub vtable: *mut (), -} -# } -``` - -[stdraw]: ../std/raw/struct.TraitObject.html - -That is, a trait object like `&Foo` consists of a "data" pointer and a "vtable" -pointer. - -The data pointer addresses the data (of some unknown type `T`) that the trait -object is storing, and the vtable pointer points to the vtable ("virtual method -table") corresponding to the implementation of `Foo` for `T`. - - -A vtable is essentially a struct of function pointers, pointing to the concrete -piece of machine code for each method in the implementation. A method call like -`trait_object.method()` will retrieve the correct pointer out of the vtable and -then do a dynamic call of it. For example: - -```{rust,ignore} -struct FooVtable { - destructor: fn(*mut ()), - size: usize, - align: usize, - method: fn(*const ()) -> String, -} - -// u8: - -fn call_method_on_u8(x: *const ()) -> String { - // the compiler guarantees that this function is only called - // with `x` pointing to a u8 - let byte: &u8 = unsafe { &*(x as *const u8) }; - - byte.method() -} - -static Foo_for_u8_vtable: FooVtable = FooVtable { - destructor: /* compiler magic */, - size: 1, - align: 1, - - // cast to a function pointer - method: call_method_on_u8 as fn(*const ()) -> String, -}; - - -// String: - -fn call_method_on_String(x: *const ()) -> String { - // the compiler guarantees that this function is only called - // with `x` pointing to a String - let string: &String = unsafe { &*(x as *const String) }; - - string.method() -} - -static Foo_for_String_vtable: FooVtable = FooVtable { - destructor: /* compiler magic */, - // values for a 64-bit computer, halve them for 32-bit ones - size: 24, - align: 8, - - method: call_method_on_String as fn(*const ()) -> String, -}; -``` - -The `destructor` field in each vtable points to a function that will clean up -any resources of the vtable's type, for `u8` it is trivial, but for `String` it -will free the memory. This is necessary for owning trait objects like -`Box`, which need to clean-up both the `Box` allocation as well as the -internal type when they go out of scope. The `size` and `align` fields store -the size of the erased type, and its alignment requirements; these are -essentially unused at the moment since the information is embedded in the -destructor, but will be used in the future, as trait objects are progressively -made more flexible. - -Suppose we've got some values that implement `Foo`, then the explicit form of -construction and use of `Foo` trait objects might look a bit like (ignoring the -type mismatches: they're all just pointers anyway): - -```{rust,ignore} -let a: String = "foo".to_string(); -let x: u8 = 1; - -// let b: &Foo = &a; -let b = TraitObject { - // store the data - data: &a, - // store the methods - vtable: &Foo_for_String_vtable -}; - -// let y: &Foo = x; -let y = TraitObject { - // store the data - data: &x, - // store the methods - vtable: &Foo_for_u8_vtable -}; - -// b.method(); -(b.vtable.method)(b.data); - -// y.method(); -(y.vtable.method)(y.data); -``` - -If `b` or `y` were owning trait objects (`Box`), there would be a -`(b.vtable.destructor)(b.data)` (respectively `y`) call when they went out of -scope. diff --git a/src/doc/trpl/static.md b/src/doc/trpl/static.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/strings.md b/src/doc/trpl/strings.md index 2c2e6a8c7c5ac..e69de29bb2d1d 100644 --- a/src/doc/trpl/strings.md +++ b/src/doc/trpl/strings.md @@ -1,61 +0,0 @@ -% Strings - -Strings are an important concept for any programmer to master. Rust's string -handling system is a bit different from other languages, due to its systems -focus. Any time you have a data structure of variable size, things can get -tricky, and strings are a re-sizable data structure. That being said, Rust's -strings also work differently than in some other systems languages, such as C. - -Let's dig into the details. A *string* is a sequence of Unicode scalar values -encoded as a stream of UTF-8 bytes. All strings are guaranteed to be -validly encoded UTF-8 sequences. Additionally, strings are not null-terminated -and can contain null bytes. - -Rust has two main types of strings: `&str` and `String`. - -The first kind is a `&str`. These are called *string slices*. String literals -are of the type `&str`: - -```{rust} -let string = "Hello there."; // string: &str -``` - -This string is statically allocated, meaning that it's saved inside our -compiled program, and exists for the entire duration it runs. The `string` -binding is a reference to this statically allocated string. String slices -have a fixed size, and cannot be mutated. - -A `String`, on the other hand, is a heap-allocated string. This string -is growable, and is also guaranteed to be UTF-8. `String`s are -commonly created by converting from a string slice using the -`to_string` method. - -```{rust} -let mut s = "Hello".to_string(); // mut s: String -println!("{}", s); - -s.push_str(", world."); -println!("{}", s); -``` - -`String`s will coerce into `&str` with an `&`: - -``` -fn takes_slice(slice: &str) { - println!("Got: {}", slice); -} - -fn main() { - let s = "Hello".to_string(); - takes_slice(&s); -} -``` - -Viewing a `String` as a `&str` is cheap, but converting the `&str` to a -`String` involves allocating memory. No reason to do that unless you have to! - -That's the basics of strings in Rust! They're probably a bit more complicated -than you are used to, if you come from a scripting language, but when the -low-level details matter, they really matter. Just remember that `String`s -allocate memory and control their data, while `&str`s are a reference to -another string, and you'll be all set. diff --git a/src/doc/trpl/structs.md b/src/doc/trpl/structs.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/syntax-and-semantics.md b/src/doc/trpl/syntax-and-semantics.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/testing.md b/src/doc/trpl/testing.md index 8cf126cad95fb..e69de29bb2d1d 100644 --- a/src/doc/trpl/testing.md +++ b/src/doc/trpl/testing.md @@ -1,432 +0,0 @@ -% Testing - -> Program testing can be a very effective way to show the presence of bugs, but -> it is hopelessly inadequate for showing their absence. -> -> Edsger W. Dijkstra, "The Humble Programmer" (1972) - -Let's talk about how to test Rust code. What we will not be talking about is -the right way to test Rust code. There are many schools of thought regarding -the right and wrong way to write tests. All of these approaches use the same -basic tools, and so we'll show you the syntax for using them. - -# The `test` attribute - -At its simplest, a test in Rust is a function that's annotated with the `test` -attribute. Let's make a new project with Cargo called `adder`: - -```bash -$ cargo new adder -$ cd adder -``` - -Cargo will automatically generate a simple test when you make a new project. -Here's the contents of `src/lib.rs`: - -```rust -#[test] -fn it_works() { -} -``` - -Note the `#[test]`. This attribute indicates that this is a test function. It -currently has no body. That's good enough to pass! We can run the tests with -`cargo test`: - -```bash -$ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a - -running 1 test -test it_works ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured - - Doc-tests adder - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured -``` - -Cargo compiled and ran our tests. There are two sets of output here: one -for the test we wrote, and another for documentation tests. We'll talk about -those later. For now, see this line: - -```text -test it_works ... ok -``` - -Note the `it_works`. This comes from the name of our function: - -```rust -fn it_works() { -# } -``` - -We also get a summary line: - -```text -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured -``` - -So why does our do-nothing test pass? Any test which doesn't `panic!` passes, -and any test that does `panic!` fails. Let's make our test fail: - -```rust -#[test] -fn it_works() { - assert!(false); -} -``` - -`assert!` is a macro provided by Rust which takes one argument: if the argument -is `true`, nothing happens. If the argument is false, it `panic!`s. Let's run -our tests again: - -```bash -$ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a - -running 1 test -test it_works ... FAILED - -failures: - ----- it_works stdout ---- - thread 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3 - - - -failures: - it_works - -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured - -thread '
' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247 -``` - -Rust indicates that our test failed: - -```text -test it_works ... FAILED -``` - -And that's reflected in the summary line: - -```text -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured -``` - -We also get a non-zero status code: - -```bash -$ echo $? -101 -``` - -This is useful if you want to integrate `cargo test` into other tooling. - -We can invert our test's failure with another attribute: `should_panic`: - -```rust -#[test] -#[should_panic] -fn it_works() { - assert!(false); -} -``` - -This test will now succeed if we `panic!` and fail if we complete. Let's try it: - -```bash -$ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a - -running 1 test -test it_works ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured - - Doc-tests adder - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured -``` - -Rust provides another macro, `assert_eq!`, that compares two arguments for -equality: - -```rust -#[test] -#[should_panic] -fn it_works() { - assert_eq!("Hello", "world"); -} -``` - -Does this test pass or fail? Because of the `should_panic` attribute, it -passes: - -```bash -$ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a - -running 1 test -test it_works ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured - - Doc-tests adder - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured -``` - -`should_panic` tests can be fragile, as it's hard to guarantee that the test -didn't fail for an unexpected reason. To help with this, an optional `expected` -parameter can be added to the `should_panic` attribute. The test harness will -make sure that the failure message contains the provided text. A safer version -of the example above would be: - -``` -#[test] -#[should_panic(expected = "assertion failed")] -fn it_works() { - assert_eq!("Hello", "world"); -} -``` - -That's all there is to the basics! Let's write one 'real' test: - -```{rust,ignore} -pub fn add_two(a: i32) -> i32 { - a + 2 -} - -#[test] -fn it_works() { - assert_eq!(4, add_two(2)); -} -``` - -This is a very common use of `assert_eq!`: call some function with -some known arguments and compare it to the expected output. - -# The `test` module - -There is one way in which our existing example is not idiomatic: it's -missing the test module. The idiomatic way of writing our example -looks like this: - -```{rust,ignore} -pub fn add_two(a: i32) -> i32 { - a + 2 -} - -#[cfg(test)] -mod test { - use super::add_two; - - #[test] - fn it_works() { - assert_eq!(4, add_two(2)); - } -} -``` - -There's a few changes here. The first is the introduction of a `mod test` with -a `cfg` attribute. The module allows us to group all of our tests together, and -to also define helper functions if needed, that don't become a part of the rest -of our crate. The `cfg` attribute only compiles our test code if we're -currently trying to run the tests. This can save compile time, and also ensures -that our tests are entirely left out of a normal build. - -The second change is the `use` declaration. Because we're in an inner module, -we need to bring our test function into scope. This can be annoying if you have -a large module, and so this is a common use of the `glob` feature. Let's change -our `src/lib.rs` to make use of it: - -```{rust,ignore} - -pub fn add_two(a: i32) -> i32 { - a + 2 -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn it_works() { - assert_eq!(4, add_two(2)); - } -} -``` - -Note the different `use` line. Now we run our tests: - -```bash -$ cargo test - Updating registry `https://github.com/rust-lang/crates.io-index` - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a - -running 1 test -test test::it_works ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured - - Doc-tests adder - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured -``` - -It works! - -The current convention is to use the `test` module to hold your "unit-style" -tests. Anything that just tests one small bit of functionality makes sense to -go here. But what about "integration-style" tests instead? For that, we have -the `tests` directory - -# The `tests` directory - -To write an integration test, let's make a `tests` directory, and -put a `tests/lib.rs` file inside, with this as its contents: - -```{rust,ignore} -extern crate adder; - -#[test] -fn it_works() { - assert_eq!(4, adder::add_two(2)); -} -``` - -This looks similar to our previous tests, but slightly different. We now have -an `extern crate adder` at the top. This is because the tests in the `tests` -directory are an entirely separate crate, and so we need to import our library. -This is also why `tests` is a suitable place to write integration-style tests: -they use the library like any other consumer of it would. - -Let's run them: - -```bash -$ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a - -running 1 test -test test::it_works ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured - - Running target/lib-c18e7d3494509e74 - -running 1 test -test it_works ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured - - Doc-tests adder - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured -``` - -Now we have three sections: our previous test is also run, as well as our new -one. - -That's all there is to the `tests` directory. The `test` module isn't needed -here, since the whole thing is focused on tests. - -Let's finally check out that third section: documentation tests. - -# Documentation tests - -Nothing is better than documentation with examples. Nothing is worse than -examples that don't actually work, because the code has changed since the -documentation has been written. To this end, Rust supports automatically -running examples in your documentation. Here's a fleshed-out `src/lib.rs` -with examples: - -```{rust,ignore} -//! The `adder` crate provides functions that add numbers to other numbers. -//! -//! # Examples -//! -//! ``` -//! assert_eq!(4, adder::add_two(2)); -//! ``` - -/// This function adds two to its argument. -/// -/// # Examples -/// -/// ``` -/// use adder::add_two; -/// -/// assert_eq!(4, add_two(2)); -/// ``` -pub fn add_two(a: i32) -> i32 { - a + 2 -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn it_works() { - assert_eq!(4, add_two(2)); - } -} -``` - -Note the module-level documentation with `//!` and the function-level -documentation with `///`. Rust's documentation supports Markdown in comments, -and so triple graves mark code blocks. It is conventional to include the -`# Examples` section, exactly like that, with examples following. - -Let's run the tests again: - -```bash -$ cargo test - Compiling adder v0.0.1 (file:///home/steve/tmp/adder) - Running target/adder-91b3e234d4ed382a - -running 1 test -test test::it_works ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured - - Running target/lib-c18e7d3494509e74 - -running 1 test -test it_works ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured - - Doc-tests adder - -running 2 tests -test add_two_0 ... ok -test _0 ... ok - -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured -``` - -Now we have all three kinds of tests running! Note the names of the -documentation tests: the `_0` is generated for the module test, and `add_two_0` -for the function test. These will auto increment with names like `add_two_1` as -you add more examples. - diff --git a/src/doc/trpl/the-stack-and-the-heap.md b/src/doc/trpl/the-stack-and-the-heap.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/tracing-macros.md b/src/doc/trpl/tracing-macros.md deleted file mode 100644 index 6226ea9f3e75a..0000000000000 --- a/src/doc/trpl/tracing-macros.md +++ /dev/null @@ -1,91 +0,0 @@ -% Tracing Macros - -The `trace_macros` feature allows you to use a special feature: tracing macro -invocations. - -In the advanced macros chapter, we defined a `bct` macro: - -```rust -macro_rules! bct { - // cmd 0: d ... => ... - (0, $($ps:tt),* ; $_d:tt) - => (bct!($($ps),*, 0 ; )); - (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*) - => (bct!($($ps),*, 0 ; $($ds),*)); - - // cmd 1p: 1 ... => 1 ... p - (1, $p:tt, $($ps:tt),* ; 1) - => (bct!($($ps),*, 1, $p ; 1, $p)); - (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*) - => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p)); - - // cmd 1p: 0 ... => 0 ... - (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) - => (bct!($($ps),*, 1, $p ; $($ds),*)); - - // halt on empty data string - ( $($ps:tt),* ; ) - => (()); -} -``` - -This is pretty complex! we can see the output - -```rust,ignore -#![feature(trace_macros)] - -macro_rules! bct { - // cmd 0: d ... => ... - (0, $($ps:tt),* ; $_d:tt) - => (bct!($($ps),*, 0 ; )); - (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*) - => (bct!($($ps),*, 0 ; $($ds),*)); - - // cmd 1p: 1 ... => 1 ... p - (1, $p:tt, $($ps:tt),* ; 1) - => (bct!($($ps),*, 1, $p ; 1, $p)); - (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*) - => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p)); - - // cmd 1p: 0 ... => 0 ... - (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) - => (bct!($($ps),*, 1, $p ; $($ds),*)); - - // halt on empty data string - ( $($ps:tt),* ; ) - => (()); -} - -fn main() { - trace_macros!(true); - - bct!(0, 0, 1, 1, 1 ; 1, 0, 1); -} -``` - -This will print out a wall of text: - -```text -bct! { 0 , 0 , 1 , 1 , 1 ; 1 , 0 , 1 } -bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 } -bct! { 1 , 1 , 1 , 0 , 0 ; 1 } -bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 1 } -bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 1 , 0 } -bct! { 1 , 1 , 1 , 0 , 0 ; 1 , 0 } -bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 0 , 1 } -bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 0 , 1 , 0 } -bct! { 1 , 1 , 1 , 0 , 0 ; 0 , 1 , 0 } -bct! { 1 , 0 , 0 , 1 , 1 ; 0 , 1 , 0 } -bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 , 0 } -``` - -And eventually, error: - -```text -18:45 error: recursion limit reached while expanding the macro `bct` - => (bct!($($ps),*, 1, $p ; $($ds),*)); - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -``` - -The `trace_macros!` call is what produces this output, showing how we match -each time. diff --git a/src/doc/trpl/trait-objects.md b/src/doc/trpl/trait-objects.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index 2986de4179b89..e69de29bb2d1d 100644 --- a/src/doc/trpl/traits.md +++ b/src/doc/trpl/traits.md @@ -1,508 +0,0 @@ -% Traits - -Do you remember the `impl` keyword, used to call a function with method -syntax? - -```{rust} -# #![feature(core)] -struct Circle { - x: f64, - y: f64, - radius: f64, -} - -impl Circle { - fn area(&self) -> f64 { - std::f64::consts::PI * (self.radius * self.radius) - } -} -``` - -Traits are similar, except that we define a trait with just the method -signature, then implement the trait for that struct. Like this: - -```{rust} -# #![feature(core)] -struct Circle { - x: f64, - y: f64, - radius: f64, -} - -trait HasArea { - fn area(&self) -> f64; -} - -impl HasArea for Circle { - fn area(&self) -> f64 { - std::f64::consts::PI * (self.radius * self.radius) - } -} -``` - -As you can see, the `trait` block looks very similar to the `impl` block, -but we don't define a body, just a type signature. When we `impl` a trait, -we use `impl Trait for Item`, rather than just `impl Item`. - -So what's the big deal? Remember the error we were getting with our generic -`inverse` function? - -```text -error: binary operation `==` cannot be applied to type `T` -``` - -We can use traits to constrain our generics. Consider this function, which -does not compile, and gives us a similar error: - -```{rust,ignore} -fn print_area(shape: T) { - println!("This shape has an area of {}", shape.area()); -} -``` - -Rust complains: - -```text -error: type `T` does not implement any method in scope named `area` -``` - -Because `T` can be any type, we can't be sure that it implements the `area` -method. But we can add a *trait constraint* to our generic `T`, ensuring -that it does: - -```{rust} -# trait HasArea { -# fn area(&self) -> f64; -# } -fn print_area(shape: T) { - println!("This shape has an area of {}", shape.area()); -} -``` - -The syntax `` means `any type that implements the HasArea trait`. -Because traits define function type signatures, we can be sure that any type -which implements `HasArea` will have an `.area()` method. - -Here's an extended example of how this works: - -```{rust} -# #![feature(core)] -trait HasArea { - fn area(&self) -> f64; -} - -struct Circle { - x: f64, - y: f64, - radius: f64, -} - -impl HasArea for Circle { - fn area(&self) -> f64 { - std::f64::consts::PI * (self.radius * self.radius) - } -} - -struct Square { - x: f64, - y: f64, - side: f64, -} - -impl HasArea for Square { - fn area(&self) -> f64 { - self.side * self.side - } -} - -fn print_area(shape: T) { - println!("This shape has an area of {}", shape.area()); -} - -fn main() { - let c = Circle { - x: 0.0f64, - y: 0.0f64, - radius: 1.0f64, - }; - - let s = Square { - x: 0.0f64, - y: 0.0f64, - side: 1.0f64, - }; - - print_area(c); - print_area(s); -} -``` - -This program outputs: - -```text -This shape has an area of 3.141593 -This shape has an area of 1 -``` - -As you can see, `print_area` is now generic, but also ensures that we -have passed in the correct types. If we pass in an incorrect type: - -```{rust,ignore} -print_area(5); -``` - -We get a compile-time error: - -```text -error: failed to find an implementation of trait main::HasArea for int -``` - -So far, we've only added trait implementations to structs, but you can -implement a trait for any type. So technically, we _could_ implement -`HasArea` for `i32`: - -```{rust} -trait HasArea { - fn area(&self) -> f64; -} - -impl HasArea for i32 { - fn area(&self) -> f64 { - println!("this is silly"); - - *self as f64 - } -} - -5.area(); -``` - -It is considered poor style to implement methods on such primitive types, even -though it is possible. - -This may seem like the Wild West, but there are two other restrictions around -implementing traits that prevent this from getting out of hand. First, traits -must be `use`d in any scope where you wish to use the trait's method. So for -example, this does not work: - -```{rust,ignore} -mod shapes { - use std::f64::consts; - - trait HasArea { - fn area(&self) -> f64; - } - - struct Circle { - x: f64, - y: f64, - radius: f64, - } - - impl HasArea for Circle { - fn area(&self) -> f64 { - consts::PI * (self.radius * self.radius) - } - } -} - -fn main() { - let c = shapes::Circle { - x: 0.0f64, - y: 0.0f64, - radius: 1.0f64, - }; - - println!("{}", c.area()); -} -``` - -Now that we've moved the structs and traits into their own module, we get an -error: - -```text -error: type `shapes::Circle` does not implement any method in scope named `area` -``` - -If we add a `use` line right above `main` and make the right things public, -everything is fine: - -```{rust} -# #![feature(core)] -mod shapes { - use std::f64::consts; - - pub trait HasArea { - fn area(&self) -> f64; - } - - pub struct Circle { - pub x: f64, - pub y: f64, - pub radius: f64, - } - - impl HasArea for Circle { - fn area(&self) -> f64 { - consts::PI * (self.radius * self.radius) - } - } -} - -use shapes::HasArea; - -fn main() { - let c = shapes::Circle { - x: 0.0f64, - y: 0.0f64, - radius: 1.0f64, - }; - - println!("{}", c.area()); -} -``` - -This means that even if someone does something bad like add methods to `int`, -it won't affect you, unless you `use` that trait. - -There's one more restriction on implementing traits. Either the trait or the -type you're writing the `impl` for must be inside your crate. So, we could -implement the `HasArea` type for `i32`, because `HasArea` is in our crate. But -if we tried to implement `Float`, a trait provided by Rust, for `i32`, we could -not, because both the trait and the type aren't in our crate. - -One last thing about traits: generic functions with a trait bound use -*monomorphization* (*mono*: one, *morph*: form), so they are statically -dispatched. What's that mean? Check out the chapter on [static and dynamic -dispatch](static-and-dynamic-dispatch.html) for more. - -## Multiple trait bounds - -You’ve seen that you can bound a generic type parameter with a trait: - -```rust -fn foo(x: T) { - x.clone(); -} -``` - -If you need more than one bound, you can use `+`: - -```rust -use std::fmt::Debug; - -fn foo(x: T) { - x.clone(); - println!("{:?}", x); -} -``` - -`T` now needs to be both `Clone` as well as `Debug`. - -## Where clause - -Writing functions with only a few generic types and a small number of trait -bounds isn't too bad, but as the number increases, the syntax gets increasingly -awkward: - -``` -use std::fmt::Debug; - -fn foo(x: T, y: K) { - x.clone(); - y.clone(); - println!("{:?}", y); -} -``` - -The name of the function is on the far left, and the parameter list is on the -far right. The bounds are getting in the way. - -Rust has a solution, and it's called a '`where` clause': - -``` -use std::fmt::Debug; - -fn foo(x: T, y: K) { - x.clone(); - y.clone(); - println!("{:?}", y); -} - -fn bar(x: T, y: K) where T: Clone, K: Clone + Debug { - x.clone(); - y.clone(); - println!("{:?}", y); -} - -fn main() { - foo("Hello", "world"); - bar("Hello", "workd"); -} -``` - -`foo()` uses the syntax we showed earlier, and `bar()` uses a `where` clause. -All you need to do is leave off the bounds when defining your type parameters, -and then add `where` after the parameter list. For longer lists, whitespace can -be added: - -``` -use std::fmt::Debug; - -fn bar(x: T, y: K) - where T: Clone, - K: Clone + Debug { - - x.clone(); - y.clone(); - println!("{:?}", y); -} -``` - -This flexibility can add clarity in complex situations. - -`where` is also more powerful than the simpler syntax. For example: - -``` -trait ConvertTo { - fn convert(&self) -> Output; -} - -impl ConvertTo for i32 { - fn convert(&self) -> i64 { *self as i64 } -} - -// can be called with T == i32 -fn normal>(x: &T) -> i64 { - x.convert() -} - -// can be called with T == i64 -fn inverse() -> T - // this is using ConvertTo as if it were "ConvertFrom" - where i32: ConvertTo { - 1i32.convert() -} -``` - -This shows off the additional feature of `where` clauses: they allow bounds -where the left-hand side is an arbitrary type (`i32` in this case), not just a -plain type parameter (like `T`). - -## Our `inverse` Example - -Back in [Generics](generics.html), we were trying to write code like this: - -```{rust,ignore} -fn inverse(x: T) -> Result { - if x == 0.0 { return Err("x cannot be zero!".to_string()); } - - Ok(1.0 / x) -} -``` - -If we try to compile it, we get this error: - -```text -error: binary operation `==` cannot be applied to type `T` -``` - -This is because `T` is too generic: we don't know if a random `T` can be -compared. For that, we can use trait bounds. It doesn't quite work, but try -this: - -```{rust,ignore} -fn inverse(x: T) -> Result { - if x == 0.0 { return Err("x cannot be zero!".to_string()); } - - Ok(1.0 / x) -} -``` - -You should get this error: - -```text -error: mismatched types: - expected `T`, - found `_` -(expected type parameter, - found floating-point variable) -``` - -So this won't work. While our `T` is `PartialEq`, we expected to have another `T`, -but instead, we found a floating-point variable. We need a different bound. `Float` -to the rescue: - -``` -# #![feature(std_misc)] -use std::num::Float; - -fn inverse(x: T) -> Result { - if x == Float::zero() { return Err("x cannot be zero!".to_string()) } - - let one: T = Float::one(); - Ok(one / x) -} -``` - -We've had to replace our generic `0.0` and `1.0` with the appropriate methods -from the `Float` trait. Both `f32` and `f64` implement `Float`, so our function -works just fine: - -``` -# #![feature(std_misc)] -# use std::num::Float; -# fn inverse(x: T) -> Result { -# if x == Float::zero() { return Err("x cannot be zero!".to_string()) } -# let one: T = Float::one(); -# Ok(one / x) -# } -println!("the inverse of {} is {:?}", 2.0f32, inverse(2.0f32)); -println!("the inverse of {} is {:?}", 2.0f64, inverse(2.0f64)); - -println!("the inverse of {} is {:?}", 0.0f32, inverse(0.0f32)); -println!("the inverse of {} is {:?}", 0.0f64, inverse(0.0f64)); -``` - -## Default methods - -There's one last feature of traits we should cover: default methods. It's -easiest just to show an example: - -```rust -trait Foo { - fn bar(&self); - - fn baz(&self) { println!("We called baz."); } -} -``` - -Implementors of the `Foo` trait need to implement `bar()`, but they don't -need to implement `baz()`. They'll get this default behavior. They can -override the default if they so choose: - -```rust -# trait Foo { -# fn bar(&self); -# fn baz(&self) { println!("We called baz."); } -# } -struct UseDefault; - -impl Foo for UseDefault { - fn bar(&self) { println!("We called bar."); } -} - -struct OverrideDefault; - -impl Foo for OverrideDefault { - fn bar(&self) { println!("We called bar."); } - - fn baz(&self) { println!("Override baz!"); } -} - -let default = UseDefault; -default.baz(); // prints "We called baz." - -let over = OverrideDefault; -over.baz(); // prints "Override baz!" -``` diff --git a/src/doc/trpl/tuple-structs.md b/src/doc/trpl/tuple-structs.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/tuples.md b/src/doc/trpl/tuples.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/type-aliases.md b/src/doc/trpl/type-aliases.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/ufcs.md b/src/doc/trpl/ufcs.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/unsafe-code.md b/src/doc/trpl/unsafe-code.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md deleted file mode 100644 index 3ca3cfd05886e..0000000000000 --- a/src/doc/trpl/unsafe.md +++ /dev/null @@ -1,183 +0,0 @@ -% Unsafe and Low-Level Code - -# Introduction - -Rust aims to provide safe abstractions over the low-level details of -the CPU and operating system, but sometimes one needs to drop down and -write code at that level. This guide aims to provide an overview of -the dangers and power one gets with Rust's unsafe subset. - -Rust provides an escape hatch in the form of the `unsafe { ... }` -block which allows the programmer to dodge some of the compiler's -checks and do a wide range of operations, such as: - -- dereferencing [raw pointers](#raw-pointers) -- calling a function via FFI ([covered by the FFI guide](ffi.html)) -- casting between types bitwise (`transmute`, aka "reinterpret cast") -- [inline assembly](#inline-assembly) - -Note that an `unsafe` block does not relax the rules about lifetimes -of `&` and the freezing of borrowed data. - -Any use of `unsafe` is the programmer saying "I know more than you" to -the compiler, and, as such, the programmer should be very sure that -they actually do know more about why that piece of code is valid. In -general, one should try to minimize the amount of unsafe code in a -code base; preferably by using the bare minimum `unsafe` blocks to -build safe interfaces. - -> **Note**: the low-level details of the Rust language are still in -> flux, and there is no guarantee of stability or backwards -> compatibility. In particular, there may be changes that do not cause -> compilation errors, but do cause semantic changes (such as invoking -> undefined behaviour). As such, extreme care is required. - -# Pointers - -## References - -One of Rust's biggest features is memory safety. This is achieved in -part via [the ownership system](ownership.html), which is how the -compiler can guarantee that every `&` reference is always valid, and, -for example, never pointing to freed memory. - -These restrictions on `&` have huge advantages. However, they also -constrain how we can use them. For example, `&` doesn't behave -identically to C's pointers, and so cannot be used for pointers in -foreign function interfaces (FFI). Additionally, both immutable (`&`) -and mutable (`&mut`) references have some aliasing and freezing -guarantees, required for memory safety. - -In particular, if you have an `&T` reference, then the `T` must not be -modified through that reference or any other reference. There are some -standard library types, e.g. `Cell` and `RefCell`, that provide inner -mutability by replacing compile time guarantees with dynamic checks at -runtime. - -An `&mut` reference has a different constraint: when an object has an -`&mut T` pointing into it, then that `&mut` reference must be the only -such usable path to that object in the whole program. That is, an -`&mut` cannot alias with any other references. - -Using `unsafe` code to incorrectly circumvent and violate these -restrictions is undefined behaviour. For example, the following -creates two aliasing `&mut` pointers, and is invalid. - -``` -use std::mem; -let mut x: u8 = 1; - -let ref_1: &mut u8 = &mut x; -let ref_2: &mut u8 = unsafe { mem::transmute(&mut *ref_1) }; - -// oops, ref_1 and ref_2 point to the same piece of data (x) and are -// both usable -*ref_1 = 10; -*ref_2 = 20; -``` - -## Raw pointers - -Rust offers two additional pointer types (*raw pointers*), written as -`*const T` and `*mut T`. They're an approximation of C's `const T*` and `T*` -respectively; indeed, one of their most common uses is for FFI, -interfacing with external C libraries. - -Raw pointers have much fewer guarantees than other pointer types -offered by the Rust language and libraries. For example, they - -- are not guaranteed to point to valid memory and are not even - guaranteed to be non-null (unlike both `Box` and `&`); -- do not have any automatic clean-up, unlike `Box`, and so require - manual resource management; -- are plain-old-data, that is, they don't move ownership, again unlike - `Box`, hence the Rust compiler cannot protect against bugs like - use-after-free; -- lack any form of lifetimes, unlike `&`, and so the compiler cannot - reason about dangling pointers; and -- have no guarantees about aliasing or mutability other than mutation - not being allowed directly through a `*const T`. - -Fortunately, they come with a redeeming feature: the weaker guarantees -mean weaker restrictions. The missing restrictions make raw pointers -appropriate as a building block for implementing things like smart -pointers and vectors inside libraries. For example, `*` pointers are -allowed to alias, allowing them to be used to write shared-ownership -types like reference counted and garbage collected pointers, and even -thread-safe shared memory types (`Rc` and the `Arc` types are both -implemented entirely in Rust). - -There are two things that you are required to be careful about -(i.e. require an `unsafe { ... }` block) with raw pointers: - -- dereferencing: they can have any value: so possible results include - a crash, a read of uninitialised memory, a use-after-free, or - reading data as normal. -- pointer arithmetic via the `offset` [intrinsic](#intrinsics) (or - `.offset` method): this intrinsic uses so-called "in-bounds" - arithmetic, that is, it is only defined behaviour if the result is - inside (or one-byte-past-the-end) of the object from which the - original pointer came. - -The latter assumption allows the compiler to optimize more -effectively. As can be seen, actually *creating* a raw pointer is not -unsafe, and neither is converting to an integer. - -### References and raw pointers - -At runtime, a raw pointer `*` and a reference pointing to the same -piece of data have an identical representation. In fact, an `&T` -reference will implicitly coerce to an `*const T` raw pointer in safe code -and similarly for the `mut` variants (both coercions can be performed -explicitly with, respectively, `value as *const T` and `value as *mut T`). - -Going the opposite direction, from `*const` to a reference `&`, is not -safe. A `&T` is always valid, and so, at a minimum, the raw pointer -`*const T` has to point to a valid instance of type `T`. Furthermore, -the resulting pointer must satisfy the aliasing and mutability laws of -references. The compiler assumes these properties are true for any -references, no matter how they are created, and so any conversion from -raw pointers is asserting that they hold. The programmer *must* -guarantee this. - -The recommended method for the conversion is - -``` -let i: u32 = 1; -// explicit cast -let p_imm: *const u32 = &i as *const u32; -let mut m: u32 = 2; -// implicit coercion -let p_mut: *mut u32 = &mut m; - -unsafe { - let ref_imm: &u32 = &*p_imm; - let ref_mut: &mut u32 = &mut *p_mut; -} -``` - -The `&*x` dereferencing style is preferred to using a `transmute`. -The latter is far more powerful than necessary, and the more -restricted operation is harder to use incorrectly; for example, it -requires that `x` is a pointer (unlike `transmute`). - - - -## Making the unsafe safe(r) - -There are various ways to expose a safe interface around some unsafe -code: - -- store pointers privately (i.e. not in public fields of public - structs), so that you can see and control all reads and writes to - the pointer in one place. -- use `assert!()` a lot: since you can't rely on the protection of the - compiler & type-system to ensure that your `unsafe` code is correct - at compile-time, use `assert!()` to verify that it is doing the - right thing at run-time. -- implement the `Drop` for resource clean-up via a destructor, and use - RAII (Resource Acquisition Is Initialization). This reduces the need - for any manual memory management by users, and automatically ensures - that clean-up is always run, even when the thread panics. -- ensure that any data stored behind a raw pointer is destroyed at the - appropriate time. diff --git a/src/doc/trpl/unsized-types.md b/src/doc/trpl/unsized-types.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/variable-bindings.md b/src/doc/trpl/variable-bindings.md index 88babd8659c2b..e69de29bb2d1d 100644 --- a/src/doc/trpl/variable-bindings.md +++ b/src/doc/trpl/variable-bindings.md @@ -1,161 +0,0 @@ -% Variable Bindings - -The first thing we'll learn about are *variable bindings*. They look like this: - -```{rust} -fn main() { - let x = 5; -} -``` - -Putting `fn main() {` in each example is a bit tedious, so we'll leave that out -in the future. If you're following along, make sure to edit your `main()` -function, rather than leaving it off. Otherwise, you'll get an error. - -In many languages, this is called a *variable*. But Rust's variable bindings -have a few tricks up their sleeves. Rust has a very powerful feature called -*pattern matching* that we'll get into detail with later, but the left -hand side of a `let` expression is a full pattern, not just a variable name. -This means we can do things like: - -```{rust} -let (x, y) = (1, 2); -``` - -After this expression is evaluated, `x` will be one, and `y` will be two. -Patterns are really powerful, but this is about all we can do with them so far. -So let's just keep this in the back of our minds as we go forward. - -Rust is a statically typed language, which means that we specify our types up -front. So why does our first example compile? Well, Rust has this thing called -*type inference*. If it can figure out what the type of something is, Rust -doesn't require you to actually type it out. - -We can add the type if we want to, though. Types come after a colon (`:`): - -```{rust} -let x: i32 = 5; -``` - -If I asked you to read this out loud to the rest of the class, you'd say "`x` -is a binding with the type `i32` and the value `five`." - -In this case we chose to represent `x` as a 32-bit signed integer. Rust has -many different primitive integer types. They begin with `i` for signed integers -and `u` for unsigned integers. The possible integer sizes are 8, 16, 32, and 64 -bits. - -In future examples, we may annotate the type in a comment. The examples will -look like this: - -```{rust} -fn main() { - let x = 5; // x: i32 -} -``` - -Note the similarities between this annotation and the syntax you use with `let`. -Including these kinds of comments is not idiomatic Rust, but we'll occasionally -include them to help you understand what the types that Rust infers are. - -By default, bindings are *immutable*. This code will not compile: - -```{ignore} -let x = 5; -x = 10; -``` - -It will give you this error: - -```text -error: re-assignment of immutable variable `x` - x = 10; - ^~~~~~~ -``` - -If you want a binding to be mutable, you can use `mut`: - -```{rust} -let mut x = 5; // mut x: i32 -x = 10; -``` - -There is no single reason that bindings are immutable by default, but we can -think about it through one of Rust's primary focuses: safety. If you forget to -say `mut`, the compiler will catch it, and let you know that you have mutated -something you may not have intended to mutate. If bindings were mutable by -default, the compiler would not be able to tell you this. If you _did_ intend -mutation, then the solution is quite easy: add `mut`. - -There are other good reasons to avoid mutable state when possible, but they're -out of the scope of this guide. In general, you can often avoid explicit -mutation, and so it is preferable in Rust. That said, sometimes, mutation is -what you need, so it's not verboten. - -Let's get back to bindings. Rust variable bindings have one more aspect that -differs from other languages: bindings are required to be initialized with a -value before you're allowed to use them. - -Let's try it out. Change your `src/main.rs` file to look like this: - -```{rust} -fn main() { - let x: i32; - - println!("Hello world!"); -} -``` - -You can use `cargo build` on the command line to build it. You'll get a warning, -but it will still print "Hello, world!": - -```text - Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world) -src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)] on by default -src/main.rs:2 let x: i32; - ^ -``` - -Rust warns us that we never use the variable binding, but since we never use it, -no harm, no foul. Things change if we try to actually use this `x`, however. Let's -do that. Change your program to look like this: - -```{rust,ignore} -fn main() { - let x: i32; - - println!("The value of x is: {}", x); -} -``` - -And try to build it. You'll get an error: - -```{bash} -$ cargo build - Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world) -src/main.rs:4:39: 4:40 error: use of possibly uninitialized variable: `x` -src/main.rs:4 println!("The value of x is: {}", x); - ^ -note: in expansion of format_args! -:2:23: 2:77 note: expansion site -:1:1: 3:2 note: in expansion of println! -src/main.rs:4:5: 4:42 note: expansion site -error: aborting due to previous error -Could not compile `hello_world`. -``` - -Rust will not let us use a value that has not been initialized. Next, let's -talk about this stuff we've added to `println!`. - -If you include two curly braces (`{}`, some call them moustaches...) in your -string to print, Rust will interpret this as a request to interpolate some sort -of value. *String interpolation* is a computer science term that means "stick -in the middle of a string." We add a comma, and then `x`, to indicate that we -want `x` to be the value we're interpolating. The comma is used to separate -arguments we pass to functions and macros, if you're passing more than one. - -When you just use the curly braces, Rust will attempt to display the -value in a meaningful way by checking out its type. If you want to specify the -format in a more detailed manner, there are a [wide number of options -available](../std/fmt/index.html). For now, we'll just stick to the default: -integers aren't very complicated to print. diff --git a/src/doc/trpl/vectors.md b/src/doc/trpl/vectors.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/doc/trpl/while-loops.md b/src/doc/trpl/while-loops.md new file mode 100644 index 0000000000000..e69de29bb2d1d From 5c3aa01045cee7d632e93cad4295fa12109e9550 Mon Sep 17 00:00:00 2001 From: Dave Huseby Date: Tue, 7 Apr 2015 16:03:14 -0700 Subject: [PATCH 20/62] disabling a test that is failing on bitrig. --- src/libstd/net/addr.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 886f252fb1926..18d8fcc8a5288 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -750,8 +750,9 @@ mod tests { assert!(tsa("localhost:23924").unwrap().contains(&a)); } + // FIXME: figure out why this fails on bitrig and fix it #[test] - #[cfg(not(windows))] + #[cfg(not(any(windows, target_os = "bitrig")))] fn to_socket_addr_str_bad() { assert!(tsa("1200::AB00:1234::2552:7777:1313:34300").is_err()); } From 0027253f188cb6986f4d1281a31bb01769178f7d Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 7 Apr 2015 22:16:02 -0400 Subject: [PATCH 21/62] Import real content. --- src/doc/trpl/SUMMARY.md | 2 +- src/doc/trpl/arrays.md | 48 ++ src/doc/trpl/associated-types.md | 202 +++++++ src/doc/trpl/attributes.md | 3 + src/doc/trpl/benchmark-tests.md | 152 +++++ src/doc/trpl/box-syntax-and-patterns.md | 100 ++++ src/doc/trpl/casting-between-types.md | 3 + src/doc/trpl/closures.md | 475 ++++++++++++++++ src/doc/trpl/comments.md | 47 ++ src/doc/trpl/compiler-plugins.md | 242 ++++++++ src/doc/trpl/concurrency.md | 358 ++++++++++++ src/doc/trpl/conditional-compilation.md | 3 + src/doc/trpl/const.md | 3 + src/doc/trpl/crates-and-modules.md | 533 +++++++++++++++++ src/doc/trpl/debug-and-display.md | 3 + src/doc/trpl/deref-coercions.md | 3 + src/doc/trpl/documentation.md | 562 ++++++++++++++++++ src/doc/trpl/drop.md | 3 + src/doc/trpl/effective-rust.md | 1 + src/doc/trpl/enums.md | 149 +++++ src/doc/trpl/error-handling.md | 301 ++++++++++ src/doc/trpl/ffi.md | 530 +++++++++++++++++ src/doc/trpl/for-loops.md | 44 ++ src/doc/trpl/functions.md | 193 +++++++ src/doc/trpl/generics.md | 177 ++++++ src/doc/trpl/getting-started.md | 1 + src/doc/trpl/glossary.md | 39 ++ src/doc/trpl/hello-cargo.md | 168 ++++++ src/doc/trpl/hello-world.md | 164 ++++++ src/doc/trpl/if.md | 157 +++++ src/doc/trpl/inline-assembly.md | 141 +++++ src/doc/trpl/installing-rust.md | 93 +++ src/doc/trpl/intrinsics.md | 25 + src/doc/trpl/iterators.md | 349 ++++++++++++ src/doc/trpl/lang-items.md | 79 +++ src/doc/trpl/learn-rust.md | 1 + src/doc/trpl/lifetimes.md | 3 + src/doc/trpl/link-args.md | 25 + src/doc/trpl/lol.txt | 1 - src/doc/trpl/macros.md | 663 ++++++++++++++++++++++ src/doc/trpl/match.md | 156 +++++ src/doc/trpl/method-syntax.md | 232 ++++++++ src/doc/trpl/move-semantics.md | 3 + src/doc/trpl/mutability.md | 3 + src/doc/trpl/nightly-rust.md | 2 +- src/doc/trpl/no-stdlib.md | 168 ++++++ src/doc/trpl/operators-and-overloading.md | 3 + src/doc/trpl/ownership.md | 555 ++++++++++++++++++ src/doc/trpl/patterns.md | 200 +++++++ src/doc/trpl/plugins.md | 0 src/doc/trpl/primitive-types.md | 3 + src/doc/trpl/references-and-borrowing.md | 3 + src/doc/trpl/slices.md | 21 + src/doc/trpl/static.md | 3 + src/doc/trpl/strings.md | 61 ++ src/doc/trpl/structs.md | 49 ++ src/doc/trpl/syntax-and-semantics.md | 1 + src/doc/trpl/testing.md | 432 ++++++++++++++ src/doc/trpl/the-stack-and-the-heap.md | 3 + src/doc/trpl/trait-objects.md | 306 ++++++++++ src/doc/trpl/traits.md | 508 +++++++++++++++++ src/doc/trpl/tuple-structs.md | 56 ++ src/doc/trpl/tuples.md | 97 ++++ src/doc/trpl/type-aliases.md | 3 + src/doc/trpl/ufcs.md | 3 + src/doc/trpl/unsafe-code.md | 183 ++++++ src/doc/trpl/unsized-types.md | 3 + src/doc/trpl/variable-bindings.md | 161 ++++++ src/doc/trpl/vectors.md | 33 ++ src/doc/trpl/while-loops.md | 83 +++ 70 files changed, 9377 insertions(+), 3 deletions(-) create mode 100644 src/doc/trpl/compiler-plugins.md delete mode 100644 src/doc/trpl/lol.txt delete mode 100644 src/doc/trpl/plugins.md diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index c9ac638098bdc..d894e1c47253b 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -58,7 +58,7 @@ * [Macros](macros.md) * [`unsafe` Code](unsafe-code.md) * [Nightly Rust](nightly-rust.md) - * [Compiler Plugins](plugins.md) + * [Compiler Plugins](compiler-plugins.md) * [Inline Assembly](inline-assembly.md) * [No stdlib](no-stdlib.md) * [Intrinsics](intrinsics.md) diff --git a/src/doc/trpl/arrays.md b/src/doc/trpl/arrays.md index e69de29bb2d1d..a6ecac962d60d 100644 --- a/src/doc/trpl/arrays.md +++ b/src/doc/trpl/arrays.md @@ -0,0 +1,48 @@ +% Arrays + +Like many programming languages, Rust has list types to represent a sequence of +things. The most basic is the *array*, a fixed-size list of elements of the +same type. By default, arrays are immutable. + +```{rust} +let a = [1, 2, 3]; // a: [i32; 3] +let mut m = [1, 2, 3]; // mut m: [i32; 3] +``` + +There's a shorthand for initializing each element of an array to the same +value. In this example, each element of `a` will be initialized to `0`: + +```{rust} +let a = [0; 20]; // a: [i32; 20] +``` + +Arrays have type `[T; N]`. We'll talk about this `T` notation later, when we +cover generics. + +You can get the number of elements in an array `a` with `a.len()`, and use +`a.iter()` to iterate over them with a for loop. This code will print each +number in order: + +```{rust} +let a = [1, 2, 3]; + +println!("a has {} elements", a.len()); +for e in a.iter() { + println!("{}", e); +} +``` + +You can access a particular element of an array with *subscript notation*: + +```{rust} +let names = ["Graydon", "Brian", "Niko"]; // names: [&str; 3] + +println!("The second name is: {}", names[1]); +``` + +Subscripts start at zero, like in most programming languages, so the first name +is `names[0]` and the second name is `names[1]`. The above example prints +`The second name is: Brian`. If you try to use a subscript that is not in the +array, you will get an error: array access is bounds-checked at run-time. Such +errant access is the source of many bugs in other systems programming +languages. diff --git a/src/doc/trpl/associated-types.md b/src/doc/trpl/associated-types.md index e69de29bb2d1d..7161cd33f89be 100644 --- a/src/doc/trpl/associated-types.md +++ b/src/doc/trpl/associated-types.md @@ -0,0 +1,202 @@ +% Associated Types + +Associated types are a powerful part of Rust's type system. They're related to +the idea of a 'type family', in other words, grouping multiple types together. That +description is a bit abstract, so let's dive right into an example. If you want +to write a `Graph` trait, you have two types to be generic over: the node type +and the edge type. So you might write a trait, `Graph`, that looks like +this: + +```rust +trait Graph { + fn has_edge(&self, &N, &N) -> bool; + fn edges(&self, &N) -> Vec; + // etc +} +``` + +While this sort of works, it ends up being awkward. For example, any function +that wants to take a `Graph` as a parameter now _also_ needs to be generic over +the `N`ode and `E`dge types too: + +```rust,ignore +fn distance>(graph: &G, start: &N, end: &N) -> u32 { ... } +``` + +Our distance calculation works regardless of our `Edge` type, so the `E` stuff in +this signature is just a distraction. + +What we really want to say is that a certain `E`dge and `N`ode type come together +to form each kind of `Graph`. We can do that with associated types: + +```rust +trait Graph { + type N; + type E; + + fn has_edge(&self, &Self::N, &Self::N) -> bool; + fn edges(&self, &Self::N) -> Vec; + // etc +} +``` + +Now, our clients can be abstract over a given `Graph`: + +```rust,ignore +fn distance(graph: &G, start: &G::N, end: &G::N) -> uint { ... } +``` + +No need to deal with the `E`dge type here! + +Let's go over all this in more detail. + +## Defining associated types + +Let's build that `Graph` trait. Here's the definition: + +```rust +trait Graph { + type N; + type E; + + fn has_edge(&self, &Self::N, &Self::N) -> bool; + fn edges(&self, &Self::N) -> Vec; +} +``` + +Simple enough. Associated types use the `type` keyword, and go inside the body +of the trait, with the functions. + +These `type` declarations can have all the same thing as functions do. For example, +if we wanted our `N` type to implement `Display`, so we can print the nodes out, +we could do this: + +```rust +use std::fmt; + +trait Graph { + type N: fmt::Display; + type E; + + fn has_edge(&self, &Self::N, &Self::N) -> bool; + fn edges(&self, &Self::N) -> Vec; +} +``` + +## Implementing associated types + +Just like any trait, traits that use associated types use the `impl` keyword to +provide implementations. Here's a simple implementation of Graph: + +```rust +# trait Graph { +# type N; +# type E; +# fn has_edge(&self, &Self::N, &Self::N) -> bool; +# fn edges(&self, &Self::N) -> Vec; +# } +struct Node; + +struct Edge; + +struct MyGraph; + +impl Graph for MyGraph { + type N = Node; + type E = Edge; + + fn has_edge(&self, n1: &Node, n2: &Node) -> bool { + true + } + + fn edges(&self, n: &Node) -> Vec { + Vec::new() + } +} +``` + +This silly implementation always returns `true` and an empty `Vec`, but it +gives you an idea of how to implement this kind of thing. We first need three +`struct`s, one for the graph, one for the node, and one for the edge. If it made +more sense to use a different type, that would work as well, we're just going to +use `struct`s for all three here. + +Next is the `impl` line, which is just like implementing any other trait. + +From here, we use `=` to define our associated types. The name the trait uses +goes on the left of the `=`, and the concrete type we're `impl`ementing this +for goes on the right. Finally, we use the concrete types in our function +declarations. + +## Trait objects with associated types + +There’s one more bit of syntax we should talk about: trait objects. If you +try to create a trait object from an associated type, like this: + +```rust,ignore +# trait Graph { +# type N; +# type E; +# fn has_edge(&self, &Self::N, &Self::N) -> bool; +# fn edges(&self, &Self::N) -> Vec; +# } +# struct Node; +# struct Edge; +# struct MyGraph; +# impl Graph for MyGraph { +# type N = Node; +# type E = Edge; +# fn has_edge(&self, n1: &Node, n2: &Node) -> bool { +# true +# } +# fn edges(&self, n: &Node) -> Vec { +# Vec::new() +# } +# } +let graph = MyGraph; +let obj = Box::new(graph) as Box; +``` + +You’ll get two errors: + +```text +error: the value of the associated type `E` (from the trait `main::Graph`) must +be specified [E0191] +let obj = Box::new(graph) as Box; + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +24:44 error: the value of the associated type `N` (from the trait +`main::Graph`) must be specified [E0191] +let obj = Box::new(graph) as Box; + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +We can’t create a trait object like this, because we don’t know the associated +types. Instead, we can write this: + +```rust +# trait Graph { +# type N; +# type E; +# fn has_edge(&self, &Self::N, &Self::N) -> bool; +# fn edges(&self, &Self::N) -> Vec; +# } +# struct Node; +# struct Edge; +# struct MyGraph; +# impl Graph for MyGraph { +# type N = Node; +# type E = Edge; +# fn has_edge(&self, n1: &Node, n2: &Node) -> bool { +# true +# } +# fn edges(&self, n: &Node) -> Vec { +# Vec::new() +# } +# } +let graph = MyGraph; +let obj = Box::new(graph) as Box>; +``` + +The `N=Node` syntax allows us to provide a concrete type, `Node`, for the `N` +type parameter. Same with `E=Edge`. If we didn’t proide this constraint, we +couldn’t be sure which `impl` to match this trait object to. diff --git a/src/doc/trpl/attributes.md b/src/doc/trpl/attributes.md index e69de29bb2d1d..e699bd85f6ed7 100644 --- a/src/doc/trpl/attributes.md +++ b/src/doc/trpl/attributes.md @@ -0,0 +1,3 @@ +% Attributes + +Coming Soon! diff --git a/src/doc/trpl/benchmark-tests.md b/src/doc/trpl/benchmark-tests.md index e69de29bb2d1d..890a2f8ae7de7 100644 --- a/src/doc/trpl/benchmark-tests.md +++ b/src/doc/trpl/benchmark-tests.md @@ -0,0 +1,152 @@ +% Benchmark tests + +Rust supports benchmark tests, which can test the performance of your +code. Let's make our `src/lib.rs` look like this (comments elided): + +```{rust,ignore} +#![feature(test)] + +extern crate test; + +pub fn add_two(a: i32) -> i32 { + a + 2 +} + +#[cfg(test)] +mod test { + use super::*; + use test::Bencher; + + #[test] + fn it_works() { + assert_eq!(4, add_two(2)); + } + + #[bench] + fn bench_add_two(b: &mut Bencher) { + b.iter(|| add_two(2)); + } +} +``` + +Note the `test` feature gate, which enables this unstable feature. + +We've imported the `test` crate, which contains our benchmarking support. +We have a new function as well, with the `bench` attribute. Unlike regular +tests, which take no arguments, benchmark tests take a `&mut Bencher`. This +`Bencher` provides an `iter` method, which takes a closure. This closure +contains the code we'd like to benchmark. + +We can run benchmark tests with `cargo bench`: + +```bash +$ cargo bench + Compiling adder v0.0.1 (file:///home/steve/tmp/adder) + Running target/release/adder-91b3e234d4ed382a + +running 2 tests +test tests::it_works ... ignored +test tests::bench_add_two ... bench: 1 ns/iter (+/- 0) + +test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured +``` + +Our non-benchmark test was ignored. You may have noticed that `cargo bench` +takes a bit longer than `cargo test`. This is because Rust runs our benchmark +a number of times, and then takes the average. Because we're doing so little +work in this example, we have a `1 ns/iter (+/- 0)`, but this would show +the variance if there was one. + +Advice on writing benchmarks: + + +* Move setup code outside the `iter` loop; only put the part you want to measure inside +* Make the code do "the same thing" on each iteration; do not accumulate or change state +* Make the outer function idempotent too; the benchmark runner is likely to run + it many times +* Make the inner `iter` loop short and fast so benchmark runs are fast and the + calibrator can adjust the run-length at fine resolution +* Make the code in the `iter` loop do something simple, to assist in pinpointing + performance improvements (or regressions) + +## Gotcha: optimizations + +There's another tricky part to writing benchmarks: benchmarks compiled with +optimizations activated can be dramatically changed by the optimizer so that +the benchmark is no longer benchmarking what one expects. For example, the +compiler might recognize that some calculation has no external effects and +remove it entirely. + +```{rust,ignore} +#![feature(test)] + +extern crate test; +use test::Bencher; + +#[bench] +fn bench_xor_1000_ints(b: &mut Bencher) { + b.iter(|| { + (0..1000).fold(0, |old, new| old ^ new); + }); +} +``` + +gives the following results + +```text +running 1 test +test bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0) + +test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured +``` + +The benchmarking runner offers two ways to avoid this. Either, the closure that +the `iter` method receives can return an arbitrary value which forces the +optimizer to consider the result used and ensures it cannot remove the +computation entirely. This could be done for the example above by adjusting the +`b.iter` call to + +```rust +# struct X; +# impl X { fn iter(&self, _: F) where F: FnMut() -> T {} } let b = X; +b.iter(|| { + // note lack of `;` (could also use an explicit `return`). + (0..1000).fold(0, |old, new| old ^ new) +}); +``` + +Or, the other option is to call the generic `test::black_box` function, which +is an opaque "black box" to the optimizer and so forces it to consider any +argument as used. + +```rust +#![feature(test)] + +extern crate test; + +# fn main() { +# struct X; +# impl X { fn iter(&self, _: F) where F: FnMut() -> T {} } let b = X; +b.iter(|| { + let n = test::black_box(1000); + + (0..n).fold(0, |a, b| a ^ b) +}) +# } +``` + +Neither of these read or modify the value, and are very cheap for small values. +Larger values can be passed indirectly to reduce overhead (e.g. +`black_box(&huge_struct)`). + +Performing either of the above changes gives the following benchmarking results + +```text +running 1 test +test bench_xor_1000_ints ... bench: 131 ns/iter (+/- 3) + +test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured +``` + +However, the optimizer can still modify a testcase in an undesirable manner +even when using either of the above. diff --git a/src/doc/trpl/box-syntax-and-patterns.md b/src/doc/trpl/box-syntax-and-patterns.md index e69de29bb2d1d..839f07d984322 100644 --- a/src/doc/trpl/box-syntax-and-patterns.md +++ b/src/doc/trpl/box-syntax-and-patterns.md @@ -0,0 +1,100 @@ +% Box Syntax and Patterns + +Currently the only stable way to create a `Box` is via the `Box::new` method. +Also it is not possible in stable Rust to destructure a `Box` in a match +pattern. The unstable `box` keyword can be used to both create and destructure +a `Box`. An example usage would be: + +``` +#![feature(box_syntax, box_patterns)] + +fn main() { + let b = Some(box 5); + match b { + Some(box n) if n < 0 => { + println!("Box contains negative number {}", n); + }, + Some(box n) if n >= 0 => { + println!("Box contains non-negative number {}", n); + }, + None => { + println!("No box"); + }, + _ => unreachable!() + } +} +``` + +Note that these features are currently hidden behind the `box_syntax` (box +creation) and `box_patterns` (destructuring and pattern matching) gates +because the syntax may still change in the future. + +# Returning Pointers + +In many languages with pointers, you'd return a pointer from a function +so as to avoid copying a large data structure. For example: + +```{rust} +struct BigStruct { + one: i32, + two: i32, + // etc + one_hundred: i32, +} + +fn foo(x: Box) -> Box { + Box::new(*x) +} + +fn main() { + let x = Box::new(BigStruct { + one: 1, + two: 2, + one_hundred: 100, + }); + + let y = foo(x); +} +``` + +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`. + +This is an antipattern in Rust. Instead, write this: + +```rust +#![feature(box_syntax)] + +struct BigStruct { + one: i32, + two: i32, + // etc + one_hundred: i32, +} + +fn foo(x: Box) -> BigStruct { + *x +} + +fn main() { + let x = Box::new(BigStruct { + one: 1, + two: 2, + one_hundred: 100, + }); + + let y: Box = box foo(x); +} +``` + +This gives you flexibility without sacrificing performance. + +You may think that this gives us terrible performance: return a value and then +immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is +smarter than that. There is no copy in this code. `main` allocates enough room +for the `box`, passes a pointer to that memory into `foo` as `x`, and then +`foo` writes the value straight into the `Box`. + +This is important enough that it bears repeating: pointers are not for +optimizing returning values from your code. Allow the caller to choose how they +want to use your output. diff --git a/src/doc/trpl/casting-between-types.md b/src/doc/trpl/casting-between-types.md index e69de29bb2d1d..8bb0ec6db0256 100644 --- a/src/doc/trpl/casting-between-types.md +++ b/src/doc/trpl/casting-between-types.md @@ -0,0 +1,3 @@ +% Casting Between Types + +Coming Soon diff --git a/src/doc/trpl/closures.md b/src/doc/trpl/closures.md index e69de29bb2d1d..e63331e5206bf 100644 --- a/src/doc/trpl/closures.md +++ b/src/doc/trpl/closures.md @@ -0,0 +1,475 @@ +% Closures + +Rust not only has named functions, but anonymous functions as well. Anonymous +functions that have an associated environment are called 'closures', because they +close over an environment. Rust has a really great implementation of them, as +we'll see. + +# Syntax + +Closures look like this: + +```rust +let plus_one = |x: i32| x + 1; + +assert_eq!(2, plus_one(1)); +``` + +We create a binding, `plus_one`, and assign it to a closure. The closure's +arguments go between the pipes (`|`), and the body is an expression, in this +case, `x + 1`. Remember that `{ }` is an expression, so we can have multi-line +closures too: + +```rust +let plus_two = |x| { + let mut result: i32 = x; + + result += 1; + result += 1; + + result +}; + +assert_eq!(4, plus_two(2)); +``` + +You'll notice a few things about closures that are a bit different than regular +functions defined with `fn`. The first of which is that we did not need to +annotate the types of arguments the closure takes or the values it returns. We +can: + +```rust +let plus_one = |x: i32| -> i32 { x + 1 }; + +assert_eq!(2, plus_one(1)); +``` + +But we don't have to. Why is this? Basically, it was chosen for ergonomic reasons. +While specifying the full type for named functions is helpful with things like +documentation and type inference, the types of closures are rarely documented +since they’re anonymous, and they don’t cause the kinds of error-at-a-distance +that inferring named function types can. + +The second is that the syntax is similar, but a bit different. I've added spaces +here to make them look a little closer: + +```rust +fn plus_one_v1 (x: i32 ) -> i32 { x + 1 } +let plus_one_v2 = |x: i32 | -> i32 { x + 1 }; +let plus_one_v3 = |x: i32 | x + 1 ; +``` + +Small differences, but they're similar in ways. + +# Closures and their environment + +Closures are called such because they 'close over their environment.' It +looks like this: + +```rust +let num = 5; +let plus_num = |x: i32| x + num; + +assert_eq!(10, plus_num(5)); +``` + +This closure, `plus_num`, refers to a `let` binding in its scope: `num`. More +specifically, it borrows the binding. If we do something that would conflict +with that binding, we get an error. Like this one: + +```rust,ignore +let mut num = 5; +let plus_num = |x: i32| x + num; + +let y = &mut num; +``` + +Which errors with: + +```text +error: cannot borrow `num` as mutable because it is also borrowed as immutable + let y = &mut num; + ^~~ +note: previous borrow of `num` occurs here due to use in closure; the immutable + borrow prevents subsequent moves or mutable borrows of `num` until the borrow + ends + let plus_num = |x| x + num; + ^~~~~~~~~~~ +note: previous borrow ends here +fn main() { + let mut num = 5; + let plus_num = |x| x + num; + + let y = &mut num; +} +^ +``` + +A verbose yet helpful error message! As it says, we can't take a mutable borrow +on `num` because the closure is already borrowing it. If we let the closure go +out of scope, we can: + +```rust +let mut num = 5; +{ + let plus_num = |x: i32| x + num; + +} // plus_num goes out of scope, borrow of num ends + +let y = &mut num; +``` + +If your closure requires it, however, Rust will take ownership and move +the environment instead: + +```rust,ignore +let nums = vec![1, 2, 3]; + +let takes_nums = || nums; + +println!("{:?}", nums); +``` + +This gives us: + +```text +note: `nums` moved into closure environment here because it has type + `[closure(()) -> collections::vec::Vec]`, which is non-copyable +let takes_nums = || nums; + ^~~~~~~ +``` + +`Vec` has ownership over its contents, and therefore, when we refer to it +in our closure, we have to take ownership of `nums`. It's the same as if we'd +passed `nums` to a function that took ownership of it. + +## `move` closures + +We can force our closure to take ownership of its environment with the `move` +keyword: + +```rust +let num = 5; + +let owns_num = move |x: i32| x + num; +``` + +Now, even though the keyword is `move`, the variables follow normal move semantics. +In this case, `5` implements `Copy`, and so `owns_num` takes ownership of a copy +of `num`. So what's the difference? + +```rust +let mut num = 5; + +{ + let mut add_num = |x: i32| num += x; + + add_num(5); +} + +assert_eq!(10, num); +``` + +So in this case, our closure took a mutable reference to `num`, and then when +we called `add_num`, it mutated the underlying value, as we'd expect. We also +needed to declare `add_num` as `mut` too, because we’re mutating its +environment. + +If we change to a `move` closure, it's different: + +```rust +let mut num = 5; + +{ + let mut add_num = move |x: i32| num += x; + + add_num(5); +} + +assert_eq!(5, num); +``` + +We only get `5`. Rather than taking a mutable borrow out on our `num`, we took +ownership of a copy. + +Another way to think about `move` closures: they give a closure its own stack +frame. Without `move`, a closure may be tied to the stack frame that created +it, while a `move` closure is self-contained. This means that you cannot +generally return a non-`move` closure from a function, for example. + +But before we talk about taking and returning closures, we should talk some more +about the way that closures are implemented. As a systems language, Rust gives +you tons of control over what your code does, and closures are no different. + +# Closure implementation + +Rust's implementation of closures is a bit different than other languages. They +are effectively syntax sugar for traits. You'll want to make sure to have read +the [traits chapter][traits] before this one, as well as the chapter on [static +and dynamic dispatch][dispatch], which talks about trait objects. + +[traits]: traits.html +[dispatch]: static-and-dynamic-dispatch.html + +Got all that? Good. + +The key to understanding how closures work under the hood is something a bit +strange: Using `()` to call a function, like `foo()`, is an overloadable +operator. From this, everything else clicks into place. In Rust, we use the +trait system to overload operators. Calling functions is no different. We have +three separate traits to overload with: + +```rust +# mod foo { +pub trait Fn : FnMut { + extern "rust-call" fn call(&self, args: Args) -> Self::Output; +} + +pub trait FnMut : FnOnce { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +pub trait FnOnce { + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} +# } +``` + +You'll notice a few differences between these traits, but a big one is `self`: +`Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This +covers all three kinds of `self` via the usual method call syntax. But we've +split them up into three traits, rather than having a single one. This gives us +a large amount of control over what kind of closures we can take. + +The `|| {}` syntax for closures is sugar for these three traits. Rust will +generate a struct for the environment, `impl` the appropriate trait, and then +use it. + +# Taking closures as arguments + +Now that we know that closures are traits, we already know how to accept and +return closures: just like any other trait! + +This also means that we can choose static vs dynamic dispatch as well. First, +let's write a function which takes something callable, calls it, and returns +the result: + +```rust +fn call_with_one(some_closure: F) -> i32 + where F : Fn(i32) -> i32 { + + some_closure(1) +} + +let answer = call_with_one(|x| x + 2); + +assert_eq!(3, answer); +``` + +We pass our closure, `|x| x + 2`, to `call_with_one`. It just does what it +suggests: it calls the closure, giving it `1` as an argument. + +Let's examine the signature of `call_with_one` in more depth: + +```rust +fn call_with_one(some_closure: F) -> i32 +# where F : Fn(i32) -> i32 { +# some_closure(1) } +``` + +We take one parameter, and it has the type `F`. We also return a `i32`. This part +isn't interesting. The next part is: + +```rust +# fn call_with_one(some_closure: F) -> i32 + where F : Fn(i32) -> i32 { +# some_closure(1) } +``` + +Because `Fn` is a trait, we can bound our generic with it. In this case, our closure +takes a `i32` as an argument and returns an `i32`, and so the generic bound we use +is `Fn(i32) -> i32`. + +There's one other key point here: because we're bounding a generic with a +trait, this will get monomorphized, and therefore, we'll be doing static +dispatch into the closure. That's pretty neat. In many langauges, closures are +inherently heap allocated, and will always involve dynamic dispatch. In Rust, +we can stack allocate our closure environment, and statically dispatch the +call. This happens quite often with iterators and their adapters, which often +take closures as arguments. + +Of course, if we want dynamic dispatch, we can get that too. A trait object +handles this case, as usual: + +```rust +fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 { + some_closure(1) +} + +let answer = call_with_one(&|x| x + 2); + +assert_eq!(3, answer); +``` + +Now we take a trait object, a `&Fn`. And we have to make a reference +to our closure when we pass it to `call_with_one`, so we use `&||`. + +# Returning closures + +It’s very common for functional-style code to return closures in various +situations. If you try to return a closure, you may run into an error. At +first, it may seem strange, but we'll figure it out. Here's how you'd probably +try to return a closure from a function: + +```rust,ignore +fn factory() -> (Fn(i32) -> Vec) { + let vec = vec![1, 2, 3]; + + |n| vec.push(n) +} + +let f = factory(); + +let answer = f(4); +assert_eq!(vec![1, 2, 3, 4], answer); +``` + +This gives us these long, related errors: + +```text +error: the trait `core::marker::Sized` is not implemented for the type +`core::ops::Fn(i32) -> collections::vec::Vec` [E0277] +f = factory(); +^ +note: `core::ops::Fn(i32) -> collections::vec::Vec` does not have a +constant size known at compile-time +f = factory(); +^ +error: the trait `core::marker::Sized` is not implemented for the type +`core::ops::Fn(i32) -> collections::vec::Vec` [E0277] +factory() -> (Fn(i32) -> Vec) { + ^~~~~~~~~~~~~~~~~~~~~ +note: `core::ops::Fn(i32) -> collections::vec::Vec` does not have a constant size known at compile-time +fa ctory() -> (Fn(i32) -> Vec) { + ^~~~~~~~~~~~~~~~~~~~~ + +``` + +In order to return something from a function, Rust needs to know what +size the return type is. But since `Fn` is a trait, it could be various +things of various sizes: many different types can implement `Fn`. An easy +way to give something a size is to take a reference to it, as references +have a known size. So we'd write this: + +```rust,ignore +fn factory() -> &(Fn(i32) -> Vec) { + let vec = vec![1, 2, 3]; + + |n| vec.push(n) +} + +let f = factory(); + +let answer = f(4); +assert_eq!(vec![1, 2, 3, 4], answer); +``` + +But we get another error: + +```text +error: missing lifetime specifier [E0106] +fn factory() -> &(Fn(i32) -> i32) { + ^~~~~~~~~~~~~~~~~ +``` + +Right. Because we have a reference, we need to give it a lifetime. But +our `factory()` function takes no arguments, so elision doesn't kick in +here. What lifetime can we choose? `'static`: + +```rust,ignore +fn factory() -> &'static (Fn(i32) -> i32) { + let num = 5; + + |x| x + num +} + +let f = factory(); + +let answer = f(1); +assert_eq!(6, answer); +``` + +But we get another error: + +```text +error: mismatched types: + expected `&'static core::ops::Fn(i32) -> i32`, + found `[closure :7:9: 7:20]` +(expected &-ptr, + found closure) [E0308] + |x| x + num + ^~~~~~~~~~~ + +``` + +This error is letting us know that we don't have a `&'static Fn(i32) -> i32`, +we have a `[closure :7:9: 7:20]`. Wait, what? + +Because each closure generates its own environment `struct` and implementation +of `Fn` and friends, these types are anonymous. They exist just solely for +this closure. So Rust shows them as `closure `, rather than some +autogenerated name. + +But why doesn't our closure implement `&'static Fn`? Well, as we discussed before, +closures borrow their environment. And in this case, our environment is based +on a stack-allocated `5`, the `num` variable binding. So the borrow has a lifetime +of the stack frame. So if we returned this closure, the function call would be +over, the stack frame would go away, and our closure is capturing an environment +of garbage memory! + +So what to do? This _almost_ works: + +```rust,ignore +fn factory() -> Box i32> { + let num = 5; + + Box::new(|x| x + num) +} +# fn main() { +let f = factory(); + +let answer = f(1); +assert_eq!(6, answer); +# } +``` + +We use a trait object, by `Box`ing up the `Fn`. There's just one last problem: + +```text +error: `num` does not live long enough +Box::new(|x| x + num) + ^~~~~~~~~~~ +``` + +We still have a reference to the parent stack frame. With one last fix, we can +make this work: + +```rust +fn factory() -> Box i32> { + let num = 5; + + Box::new(move |x| x + num) +} +# fn main() { +let f = factory(); + +let answer = f(1); +assert_eq!(6, answer); +# } +``` + +By making the inner closure a `move Fn`, we create a new stack frame for our +closure. By `Box`ing it up, we've given it a known size, and allowing it to +escape our stack frame. diff --git a/src/doc/trpl/comments.md b/src/doc/trpl/comments.md index e69de29bb2d1d..441496e6a755b 100644 --- a/src/doc/trpl/comments.md +++ b/src/doc/trpl/comments.md @@ -0,0 +1,47 @@ +% Comments + +Now that we have some functions, it's a good idea to learn about comments. +Comments are notes that you leave to other programmers to help explain things +about your code. The compiler mostly ignores them. + +Rust has two kinds of comments that you should care about: *line comments* +and *doc comments*. + +```{rust} +// Line comments are anything after '//' and extend to the end of the line. + +let x = 5; // this is also a line comment. + +// If you have a long explanation for something, you can put line comments next +// to each other. Put a space between the // and your comment so that it's +// more readable. +``` + +The other kind of comment is a doc comment. Doc comments use `///` instead of +`//`, and support Markdown notation inside: + +```{rust} +/// `hello` is a function that prints a greeting that is personalized based on +/// the name given. +/// +/// # Arguments +/// +/// * `name` - The name of the person you'd like to greet. +/// +/// # Examples +/// +/// ```rust +/// let name = "Steve"; +/// hello(name); // prints "Hello, Steve!" +/// ``` +fn hello(name: &str) { + println!("Hello, {}!", name); +} +``` + +When writing doc comments, adding sections for any arguments, return values, +and providing some examples of usage is very, very helpful. Don't worry about +the `&str`, we'll get to it soon. + +You can use the [`rustdoc`](documentation.html) tool to generate HTML documentation +from these doc comments. diff --git a/src/doc/trpl/compiler-plugins.md b/src/doc/trpl/compiler-plugins.md new file mode 100644 index 0000000000000..9eb22a7f6985a --- /dev/null +++ b/src/doc/trpl/compiler-plugins.md @@ -0,0 +1,242 @@ +% Compiler Plugins + +# Introduction + +`rustc` can load compiler plugins, which are user-provided libraries that +extend the compiler's behavior with new syntax extensions, lint checks, etc. + +A plugin is a dynamic library crate with a designated *registrar* function that +registers extensions with `rustc`. Other crates can load these extensions using +the crate attribute `#![plugin(...)]`. See the +[`rustc::plugin`](../rustc/plugin/index.html) documentation for more about the +mechanics of defining and loading a plugin. + +If present, arguments passed as `#![plugin(foo(... args ...))]` are not +interpreted by rustc itself. They are provided to the plugin through the +`Registry`'s [`args` method](../rustc/plugin/registry/struct.Registry.html#method.args). + +In the vast majority of cases, a plugin should *only* be used through +`#![plugin]` and not through an `extern crate` item. Linking a plugin would +pull in all of libsyntax and librustc as dependencies of your crate. This is +generally unwanted unless you are building another plugin. The +`plugin_as_library` lint checks these guidelines. + +The usual practice is to put compiler plugins in their own crate, separate from +any `macro_rules!` macros or ordinary Rust code meant to be used by consumers +of a library. + +# Syntax extensions + +Plugins can extend Rust's syntax in various ways. One kind of syntax extension +is the procedural macro. These are invoked the same way as [ordinary +macros](macros.html), but the expansion is performed by arbitrary Rust +code that manipulates [syntax trees](../syntax/ast/index.html) at +compile time. + +Let's write a plugin +[`roman_numerals.rs`](https://github.com/rust-lang/rust/tree/master/src/test/auxiliary/roman_numerals.rs) +that implements Roman numeral integer literals. + +```ignore +#![crate_type="dylib"] +#![feature(plugin_registrar, rustc_private)] + +extern crate syntax; +extern crate rustc; + +use syntax::codemap::Span; +use syntax::parse::token; +use syntax::ast::{TokenTree, TtToken}; +use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; +use syntax::ext::build::AstBuilder; // trait for expr_usize +use rustc::plugin::Registry; + +fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) + -> Box { + + static NUMERALS: &'static [(&'static str, u32)] = &[ + ("M", 1000), ("CM", 900), ("D", 500), ("CD", 400), + ("C", 100), ("XC", 90), ("L", 50), ("XL", 40), + ("X", 10), ("IX", 9), ("V", 5), ("IV", 4), + ("I", 1)]; + + let text = match args { + [TtToken(_, token::Ident(s, _))] => token::get_ident(s).to_string(), + _ => { + cx.span_err(sp, "argument should be a single identifier"); + return DummyResult::any(sp); + } + }; + + let mut text = &*text; + let mut total = 0; + while !text.is_empty() { + match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) { + Some(&(rn, val)) => { + total += val; + text = &text[rn.len()..]; + } + None => { + cx.span_err(sp, "invalid Roman numeral"); + return DummyResult::any(sp); + } + } + } + + MacEager::expr(cx.expr_u32(sp, total)) +} + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_macro("rn", expand_rn); +} +``` + +Then we can use `rn!()` like any other macro: + +```ignore +#![feature(plugin)] +#![plugin(roman_numerals)] + +fn main() { + assert_eq!(rn!(MMXV), 2015); +} +``` + +The advantages over a simple `fn(&str) -> u32` are: + +* The (arbitrarily complex) conversion is done at compile time. +* Input validation is also performed at compile time. +* It can be extended to allow use in patterns, which effectively gives + a way to define new literal syntax for any data type. + +In addition to procedural macros, you can define new +[`derive`](../reference.html#derive)-like attributes and other kinds of +extensions. See +[`Registry::register_syntax_extension`](../rustc/plugin/registry/struct.Registry.html#method.register_syntax_extension) +and the [`SyntaxExtension` +enum](http://doc.rust-lang.org/syntax/ext/base/enum.SyntaxExtension.html). For +a more involved macro example, see +[`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs). + + +## Tips and tricks + +Some of the [macro debugging tips](macros.html#debugging-macro-code) are applicable. + +You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into +higher-level syntax elements like expressions: + +```ignore +fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) + -> Box { + + let mut parser = cx.new_parser_from_tts(args); + + let expr: P = parser.parse_expr(); +``` + +Looking through [`libsyntax` parser +code](https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs) +will give you a feel for how the parsing infrastructure works. + +Keep the [`Span`s](../syntax/codemap/struct.Span.html) of +everything you parse, for better error reporting. You can wrap +[`Spanned`](../syntax/codemap/struct.Spanned.html) around +your custom data structures. + +Calling +[`ExtCtxt::span_fatal`](../syntax/ext/base/struct.ExtCtxt.html#method.span_fatal) +will immediately abort compilation. It's better to instead call +[`ExtCtxt::span_err`](../syntax/ext/base/struct.ExtCtxt.html#method.span_err) +and return +[`DummyResult`](../syntax/ext/base/struct.DummyResult.html), +so that the compiler can continue and find further errors. + +To print syntax fragments for debugging, you can use +[`span_note`](../syntax/ext/base/struct.ExtCtxt.html#method.span_note) together +with +[`syntax::print::pprust::*_to_string`](http://doc.rust-lang.org/syntax/print/pprust/index.html#functions). + +The example above produced an integer literal using +[`AstBuilder::expr_usize`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_usize). +As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of +[quasiquote macros](../syntax/ext/quote/index.html). They are undocumented and +very rough around the edges. However, the implementation may be a good +starting point for an improved quasiquote as an ordinary plugin library. + + +# Lint plugins + +Plugins can extend [Rust's lint +infrastructure](../reference.html#lint-check-attributes) with additional checks for +code style, safety, etc. You can see +[`src/test/auxiliary/lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs) +for a full example, the core of which is reproduced here: + +```ignore +declare_lint!(TEST_LINT, Warn, + "Warn about items named 'lintme'") + +struct Pass; + +impl LintPass for Pass { + fn get_lints(&self) -> LintArray { + lint_array!(TEST_LINT) + } + + fn check_item(&mut self, cx: &Context, it: &ast::Item) { + let name = token::get_ident(it.ident); + if name.get() == "lintme" { + cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"); + } + } +} + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_lint_pass(box Pass as LintPassObject); +} +``` + +Then code like + +```ignore +#![plugin(lint_plugin_test)] + +fn lintme() { } +``` + +will produce a compiler warning: + +```txt +foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default +foo.rs:4 fn lintme() { } + ^~~~~~~~~~~~~~~ +``` + +The components of a lint plugin are: + +* one or more `declare_lint!` invocations, which define static + [`Lint`](../rustc/lint/struct.Lint.html) structs; + +* a struct holding any state needed by the lint pass (here, none); + +* a [`LintPass`](../rustc/lint/trait.LintPass.html) + implementation defining how to check each syntax element. A single + `LintPass` may call `span_lint` for several different `Lint`s, but should + register them all through the `get_lints` method. + +Lint passes are syntax traversals, but they run at a late stage of compilation +where type information is available. `rustc`'s [built-in +lints](https://github.com/rust-lang/rust/blob/master/src/librustc/lint/builtin.rs) +mostly use the same infrastructure as lint plugins, and provide examples of how +to access type information. + +Lints defined by plugins are controlled by the usual [attributes and compiler +flags](../reference.html#lint-check-attributes), e.g. `#[allow(test_lint)]` or +`-A test-lint`. These identifiers are derived from the first argument to +`declare_lint!`, with appropriate case and punctuation conversion. + +You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`, +including those provided by plugins loaded by `foo.rs`. diff --git a/src/doc/trpl/concurrency.md b/src/doc/trpl/concurrency.md index e69de29bb2d1d..f9358f28b0194 100644 --- a/src/doc/trpl/concurrency.md +++ b/src/doc/trpl/concurrency.md @@ -0,0 +1,358 @@ +% Concurrency + +Concurrency and parallelism are incredibly important topics in computer +science, and are also a hot topic in industry today. Computers are gaining more +and more cores, yet many programmers aren't prepared to fully utilize them. + +Rust's memory safety features also apply to its concurrency story too. Even +concurrent Rust programs must be memory safe, having no data races. Rust's type +system is up to the task, and gives you powerful ways to reason about +concurrent code at compile time. + +Before we talk about the concurrency features that come with Rust, it's important +to understand something: Rust is low-level enough that all of this is provided +by the standard library, not by the language. This means that if you don't like +some aspect of the way Rust handles concurrency, you can implement an alternative +way of doing things. [mio](https://github.com/carllerche/mio) is a real-world +example of this principle in action. + +## Background: `Send` and `Sync` + +Concurrency is difficult to reason about. In Rust, we have a strong, static +type system to help us reason about our code. As such, Rust gives us two traits +to help us make sense of code that can possibly be concurrent. + +### `Send` + +The first trait we're going to talk about is +[`Send`](../std/marker/trait.Send.html). When a type `T` implements `Send`, it indicates +to the compiler that something of this type is able to have ownership transferred +safely between threads. + +This is important to enforce certain restrictions. For example, if we have a +channel connecting two threads, we would want to be able to send some data +down the channel and to the other thread. Therefore, we'd ensure that `Send` was +implemented for that type. + +In the opposite way, if we were wrapping a library with FFI that isn't +threadsafe, we wouldn't want to implement `Send`, and so the compiler will help +us enforce that it can't leave the current thread. + +### `Sync` + +The second of these traits is called [`Sync`](../std/marker/trait.Sync.html). +When a type `T` implements `Sync`, it indicates to the compiler that something +of this type has no possibility of introducing memory unsafety when used from +multiple threads concurrently. + +For example, sharing immutable data with an atomic reference count is +threadsafe. Rust provides a type like this, `Arc`, and it implements `Sync`, +so it is safe to share between threads. + +These two traits allow you to use the type system to make strong guarantees +about the properties of your code under concurrency. Before we demonstrate +why, we need to learn how to create a concurrent Rust program in the first +place! + +## Threads + +Rust's standard library provides a library for 'threads', which allow you to +run Rust code in parallel. Here's a basic example of using `std::thread`: + +``` +use std::thread; + +fn main() { + thread::scoped(|| { + println!("Hello from a thread!"); + }); +} +``` + +The `thread::scoped()` method accepts a closure, which is executed in a new +thread. It's called `scoped` because this thread returns a join guard: + +``` +use std::thread; + +fn main() { + let guard = thread::scoped(|| { + println!("Hello from a thread!"); + }); + + // guard goes out of scope here +} +``` + +When `guard` goes out of scope, it will block execution until the thread is +finished. If we didn't want this behaviour, we could use `thread::spawn()`: + +``` +use std::thread; + +fn main() { + thread::spawn(|| { + println!("Hello from a thread!"); + }); + + thread::sleep_ms(50); +} +``` + +We need to `sleep` here because when `main()` ends, it kills all of the +running threads. + +[`scoped`](std/thread/struct.Builder.html#method.scoped) has an interesting +type signature: + +```text +fn scoped<'a, T, F>(self, f: F) -> JoinGuard<'a, T> + where T: Send + 'a, + F: FnOnce() -> T, + F: Send + 'a +``` + +Specifically, `F`, the closure that we pass to execute in the new thread. It +has two restrictions: It must be a `FnOnce` from `()` to `T`. Using `FnOnce` +allows the closure to take ownership of any data it mentions from the parent +thread. The other restriction is that `F` must be `Send`. We aren't allowed to +transfer this ownership unless the type thinks that's okay. + +Many languages have the ability to execute threads, but it's wildly unsafe. +There are entire books about how to prevent errors that occur from shared +mutable state. Rust helps out with its type system here as well, by preventing +data races at compile time. Let's talk about how you actually share things +between threads. + +## Safe Shared Mutable State + +Due to Rust's type system, we have a concept that sounds like a lie: "safe +shared mutable state." Many programmers agree that shared mutable state is +very, very bad. + +Someone once said this: + +> Shared mutable state is the root of all evil. Most languages attempt to deal +> with this problem through the 'mutable' part, but Rust deals with it by +> solving the 'shared' part. + +The same [ownership system](ownership.html) that helps prevent using pointers +incorrectly also helps rule out data races, one of the worst kinds of +concurrency bugs. + +As an example, here is a Rust program that would have a data race in many +languages. It will not compile: + +```ignore +use std::thread; + +fn main() { + let mut data = vec![1u32, 2, 3]; + + for i in 0..2 { + thread::spawn(move || { + data[i] += 1; + }); + } + + thread::sleep_ms(50); +} +``` + +This gives us an error: + +```text +8:17 error: capture of moved value: `data` + data[i] += 1; + ^~~~ +``` + +In this case, we know that our code _should_ be safe, but Rust isn't sure. And +it's actually not safe: if we had a reference to `data` in each thread, and the +thread takes ownership of the reference, we have three owners! That's bad. We +can fix this by using the `Arc` type, which is an atomic reference counted +pointer. The 'atomic' part means that it's safe to share across threads. + +`Arc` assumes one more property about its contents to ensure that it is safe +to share across threads: it assumes its contents are `Sync`. But in our +case, we want to be able to mutate the value. We need a type that can ensure +only one person at a time can mutate what's inside. For that, we can use the +`Mutex` type. Here's the second version of our code. It still doesn't work, +but for a different reason: + +```ignore +use std::thread; +use std::sync::Mutex; + +fn main() { + let mut data = Mutex::new(vec![1u32, 2, 3]); + + for i in 0..2 { + let data = data.lock().unwrap(); + thread::spawn(move || { + data[i] += 1; + }); + } + + thread::sleep_ms(50); +} +``` + +Here's the error: + +```text +:9:9: 9:22 error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec>` [E0277] +:11 thread::spawn(move || { + ^~~~~~~~~~~~~ +:9:9: 9:22 note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec>` cannot be sent between threads safely +:11 thread::spawn(move || { + ^~~~~~~~~~~~~ +``` + +You see, [`Mutex`](std/sync/struct.Mutex.html) has a +[`lock`](http://doc.rust-lang.org/nightly/std/sync/struct.Mutex.html#method.lock) +method which has this signature: + +```ignore +fn lock(&self) -> LockResult> +``` + +Because `Send` is not implemented for `MutexGuard`, we can't transfer the +guard across thread boundaries, which gives us our error. + +We can use `Arc` to fix this. Here's the working version: + +``` +use std::sync::{Arc, Mutex}; +use std::thread; + +fn main() { + let data = Arc::new(Mutex::new(vec![1u32, 2, 3])); + + for i in 0..2 { + let data = data.clone(); + thread::spawn(move || { + let mut data = data.lock().unwrap(); + data[i] += 1; + }); + } + + thread::sleep_ms(50); +} +``` + +We now call `clone()` on our `Arc`, which increases the internal count. This +handle is then moved into the new thread. Let's examine the body of the +thread more closely: + +```rust +# use std::sync::{Arc, Mutex}; +# use std::thread; +# fn main() { +# let data = Arc::new(Mutex::new(vec![1u32, 2, 3])); +# for i in 0..2 { +# let data = data.clone(); +thread::spawn(move || { + let mut data = data.lock().unwrap(); + data[i] += 1; +}); +# } +# thread::sleep_ms(50); +# } +``` + +First, we call `lock()`, which acquires the mutex's lock. Because this may fail, +it returns an `Result`, and because this is just an example, we `unwrap()` +it to get a reference to the data. Real code would have more robust error handling +here. We're then free to mutate it, since we have the lock. + +Lastly, while the threads are running, we wait on a short timer. But +this is not ideal: we may have picked a reasonable amount of time to +wait but it's more likely we'll either be waiting longer than +necessary or not long enough, depending on just how much time the +threads actually take to finish computing when the program runs. + +A more precise alternative to the timer would be to use one of the +mechanisms provided by the Rust standard library for synchronizing +threads with each other. Let's talk about one of them: channels. + +## Channels + +Here's a version of our code that uses channels for synchronization, rather +than waiting for a specific time: + +``` +use std::sync::{Arc, Mutex}; +use std::thread; +use std::sync::mpsc; + +fn main() { + let data = Arc::new(Mutex::new(0u32)); + + let (tx, rx) = mpsc::channel(); + + for _ in 0..10 { + let (data, tx) = (data.clone(), tx.clone()); + + thread::spawn(move || { + let mut data = data.lock().unwrap(); + *data += 1; + + tx.send(()); + }); + } + + for _ in 0..10 { + rx.recv(); + } +} +``` + +We use the `mpsc::channel()` method to construct a new channel. We just `send` +a simple `()` down the channel, and then wait for ten of them to come back. + +While this channel is just sending a generic signal, we can send any data that +is `Send` over the channel! + +``` +use std::thread; +use std::sync::mpsc; + +fn main() { + let (tx, rx) = mpsc::channel(); + + for _ in 0..10 { + let tx = tx.clone(); + + thread::spawn(move || { + let answer = 42u32; + + tx.send(answer); + }); + } + + rx.recv().ok().expect("Could not receive answer"); +} +``` + +A `u32` is `Send` because we can make a copy. So we create a thread, ask it to calculate +the answer, and then it `send()`s us the answer over the channel. + + +## Panics + +A `panic!` will crash the currently executing thread. You can use Rust's +threads as a simple isolation mechanism: + +``` +use std::thread; + +let result = thread::spawn(move || { + panic!("oops!"); +}).join(); + +assert!(result.is_err()); +``` + +Our `Thread` gives us a `Result` back, which allows us to check if the thread +has panicked or not. diff --git a/src/doc/trpl/conditional-compilation.md b/src/doc/trpl/conditional-compilation.md index e69de29bb2d1d..40367fa844d2e 100644 --- a/src/doc/trpl/conditional-compilation.md +++ b/src/doc/trpl/conditional-compilation.md @@ -0,0 +1,3 @@ +% Conditional Compilation + +Coming Soon! diff --git a/src/doc/trpl/const.md b/src/doc/trpl/const.md index e69de29bb2d1d..9234c4fc2f9e1 100644 --- a/src/doc/trpl/const.md +++ b/src/doc/trpl/const.md @@ -0,0 +1,3 @@ +% `const` + +Coming soon! diff --git a/src/doc/trpl/crates-and-modules.md b/src/doc/trpl/crates-and-modules.md index e69de29bb2d1d..83e8cc629fd5e 100644 --- a/src/doc/trpl/crates-and-modules.md +++ b/src/doc/trpl/crates-and-modules.md @@ -0,0 +1,533 @@ +% Crates and Modules + +When a project starts getting large, it's considered good software +engineering practice to split it up into a bunch of smaller pieces, and then +fit them together. It's also important to have a well-defined interface, so +that some of your functionality is private, and some is public. To facilitate +these kinds of things, Rust has a module system. + +# Basic terminology: Crates and Modules + +Rust has two distinct terms that relate to the module system: *crate* and +*module*. A crate is synonymous with a *library* or *package* in other +languages. Hence "Cargo" as the name of Rust's package management tool: you +ship your crates to others with Cargo. Crates can produce an executable or a +library, depending on the project. + +Each crate has an implicit *root module* that contains the code for that crate. +You can then define a tree of sub-modules under that root module. Modules allow +you to partition your code within the crate itself. + +As an example, let's make a *phrases* crate, which will give us various phrases +in different languages. To keep things simple, we'll stick to "greetings" and +"farewells" as two kinds of phrases, and use English and Japanese (日本語) as +two languages for those phrases to be in. We'll use this module layout: + +```text + +-----------+ + +---| greetings | + | +-----------+ + +---------+ | + +---| english |---+ + | +---------+ | +-----------+ + | +---| farewells | ++---------+ | +-----------+ +| phrases |---+ ++---------+ | +-----------+ + | +---| greetings | + | +----------+ | +-----------+ + +---| japanese |--+ + +----------+ | + | +-----------+ + +---| farewells | + +-----------+ +``` + +In this example, `phrases` is the name of our crate. All of the rest are +modules. You can see that they form a tree, branching out from the crate +*root*, which is the root of the tree: `phrases` itself. + +Now that we have a plan, let's define these modules in code. To start, +generate a new crate with Cargo: + +```bash +$ cargo new phrases +$ cd phrases +``` + +If you remember, this generates a simple project for us: + +```bash +$ tree . +. +├── Cargo.toml +└── src + └── lib.rs + +1 directory, 2 files +``` + +`src/lib.rs` is our crate root, corresponding to the `phrases` in our diagram +above. + +# Defining Modules + +To define each of our modules, we use the `mod` keyword. Let's make our +`src/lib.rs` look like this: + +``` +mod english { + mod greetings { + } + + mod farewells { + } +} + +mod japanese { + mod greetings { + } + + mod farewells { + } +} +``` + +After the `mod` keyword, you give the name of the module. Module names follow +the conventions for other Rust identifiers: `lower_snake_case`. The contents of +each module are within curly braces (`{}`). + +Within a given `mod`, you can declare sub-`mod`s. We can refer to sub-modules +with double-colon (`::`) notation: our four nested modules are +`english::greetings`, `english::farewells`, `japanese::greetings`, and +`japanese::farewells`. Because these sub-modules are namespaced under their +parent module, the names don't conflict: `english::greetings` and +`japanese::greetings` are distinct, even though their names are both +`greetings`. + +Because this crate does not have a `main()` function, and is called `lib.rs`, +Cargo will build this crate as a library: + +```bash +$ cargo build + Compiling phrases v0.0.1 (file:///home/you/projects/phrases) +$ ls target/debug +build deps examples libphrases-a7448e02a0468eaa.rlib native +``` + +`libphrase-hash.rlib` is the compiled crate. Before we see how to use this +crate from another crate, let's break it up into multiple files. + +# Multiple file crates + +If each crate were just one file, these files would get very large. It's often +easier to split up crates into multiple files, and Rust supports this in two +ways. + +Instead of declaring a module like this: + +```{rust,ignore} +mod english { + // contents of our module go here +} +``` + +We can instead declare our module like this: + +```{rust,ignore} +mod english; +``` + +If we do that, Rust will expect to find either a `english.rs` file, or a +`english/mod.rs` file with the contents of our module. + +Note that in these files, you don't need to re-declare the module: that's +already been done with the initial `mod` declaration. + +Using these two techniques, we can break up our crate into two directories and +seven files: + +```bash +$ tree . +. +├── Cargo.lock +├── Cargo.toml +├── src +│   ├── english +│   │   ├── farewells.rs +│   │   ├── greetings.rs +│   │   └── mod.rs +│   ├── japanese +│   │   ├── farewells.rs +│   │   ├── greetings.rs +│   │   └── mod.rs +│   └── lib.rs +└── target + └── debug + ├── build + ├── deps + ├── examples + ├── libphrases-a7448e02a0468eaa.rlib + └── native +``` + +`src/lib.rs` is our crate root, and looks like this: + +```{rust,ignore} +mod english; +mod japanese; +``` + +These two declarations tell Rust to look for either `src/english.rs` and +`src/japanese.rs`, or `src/english/mod.rs` and `src/japanese/mod.rs`, depending +on our preference. In this case, because our modules have sub-modules, we've +chosen the second. Both `src/english/mod.rs` and `src/japanese/mod.rs` look +like this: + +```{rust,ignore} +mod greetings; +mod farewells; +``` + +Again, these declarations tell Rust to look for either +`src/english/greetings.rs` and `src/japanese/greetings.rs` or +`src/english/farewells/mod.rs` and `src/japanese/farewells/mod.rs`. Because +these sub-modules don't have their own sub-modules, we've chosen to make them +`src/english/greetings.rs` and `src/japanese/farewells.rs`. Whew! + +The contents of `src/english/greetings.rs` and `src/japanese/farewells.rs` are +both empty at the moment. Let's add some functions. + +Put this in `src/english/greetings.rs`: + +```rust +fn hello() -> String { + "Hello!".to_string() +} +``` + +Put this in `src/english/farewells.rs`: + +```rust +fn goodbye() -> String { + "Goodbye.".to_string() +} +``` + +Put this in `src/japanese/greetings.rs`: + +```rust +fn hello() -> String { + "こんにちは".to_string() +} +``` + +Of course, you can copy and paste this from this web page, or just type +something else. It's not important that you actually put "konnichiwa" to learn +about the module system. + +Put this in `src/japanese/farewells.rs`: + +```rust +fn goodbye() -> String { + "さようなら".to_string() +} +``` + +(This is "Sayōnara", if you're curious.) + +Now that we have some functionality in our crate, let's try to use it from +another crate. + +# Importing External Crates + +We have a library crate. Let's make an executable crate that imports and uses +our library. + +Make a `src/main.rs` and put this in it (it won't quite compile yet): + +```rust,ignore +extern crate phrases; + +fn main() { + println!("Hello in English: {}", phrases::english::greetings::hello()); + println!("Goodbye in English: {}", phrases::english::farewells::goodbye()); + + println!("Hello in Japanese: {}", phrases::japanese::greetings::hello()); + println!("Goodbye in Japanese: {}", phrases::japanese::farewells::goodbye()); +} +``` + +The `extern crate` declaration tells Rust that we need to compile and link to +the `phrases` crate. We can then use `phrases`' modules in this one. As we +mentioned earlier, you can use double colons to refer to sub-modules and the +functions inside of them. + +Also, Cargo assumes that `src/main.rs` is the crate root of a binary crate, +rather than a library crate. Our package now has two crates: `src/lib.rs` and +`src/main.rs`. This pattern is quite common for executable crates: most +functionality is in a library crate, and the executable crate uses that +library. This way, other programs can also use the library crate, and it's also +a nice separation of concerns. + +This doesn't quite work yet, though. We get four errors that look similar to +this: + +```bash +$ cargo build + Compiling phrases v0.0.1 (file:///home/you/projects/phrases) +src/main.rs:4:38: 4:72 error: function `hello` is private +src/main.rs:4 println!("Hello in English: {}", phrases::english::greetings::hello()); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +note: in expansion of format_args! +:2:25: 2:58 note: expansion site +:1:1: 2:62 note: in expansion of print! +:3:1: 3:54 note: expansion site +:1:1: 3:58 note: in expansion of println! +phrases/src/main.rs:4:5: 4:76 note: expansion site +``` + +By default, everything is private in Rust. Let's talk about this in some more +depth. + +# Exporting a Public Interface + +Rust allows you to precisely control which aspects of your interface are +public, and so private is the default. To make things public, you use the `pub` +keyword. Let's focus on the `english` module first, so let's reduce our `src/main.rs` +to just this: + +```{rust,ignore} +extern crate phrases; + +fn main() { + println!("Hello in English: {}", phrases::english::greetings::hello()); + println!("Goodbye in English: {}", phrases::english::farewells::goodbye()); +} +``` + +In our `src/lib.rs`, let's add `pub` to the `english` module declaration: + +```{rust,ignore} +pub mod english; +mod japanese; +``` + +And in our `src/english/mod.rs`, let's make both `pub`: + +```{rust,ignore} +pub mod greetings; +pub mod farewells; +``` + +In our `src/english/greetings.rs`, let's add `pub` to our `fn` declaration: + +```{rust,ignore} +pub fn hello() -> String { + "Hello!".to_string() +} +``` + +And also in `src/english/farewells.rs`: + +```{rust,ignore} +pub fn goodbye() -> String { + "Goodbye.".to_string() +} +``` + +Now, our crate compiles, albeit with warnings about not using the `japanese` +functions: + +```bash +$ cargo run + Compiling phrases v0.0.1 (file:///home/you/projects/phrases) +src/japanese/greetings.rs:1:1: 3:2 warning: function is never used: `hello`, #[warn(dead_code)] on by default +src/japanese/greetings.rs:1 fn hello() -> String { +src/japanese/greetings.rs:2 "こんにちは".to_string() +src/japanese/greetings.rs:3 } +src/japanese/farewells.rs:1:1: 3:2 warning: function is never used: `goodbye`, #[warn(dead_code)] on by default +src/japanese/farewells.rs:1 fn goodbye() -> String { +src/japanese/farewells.rs:2 "さようなら".to_string() +src/japanese/farewells.rs:3 } + Running `target/debug/phrases` +Hello in English: Hello! +Goodbye in English: Goodbye. +``` + +Now that our functions are public, we can use them. Great! However, typing out +`phrases::english::greetings::hello()` is very long and repetitive. Rust has +another keyword for importing names into the current scope, so that you can +refer to them with shorter names. Let's talk about `use`. + +# Importing Modules with `use` + +Rust has a `use` keyword, which allows us to import names into our local scope. +Let's change our `src/main.rs` to look like this: + +```{rust,ignore} +extern crate phrases; + +use phrases::english::greetings; +use phrases::english::farewells; + +fn main() { + println!("Hello in English: {}", greetings::hello()); + println!("Goodbye in English: {}", farewells::goodbye()); +} +``` + +The two `use` lines import each module into the local scope, so we can refer to +the functions by a much shorter name. By convention, when importing functions, it's +considered best practice to import the module, rather than the function directly. In +other words, you _can_ do this: + +```{rust,ignore} +extern crate phrases; + +use phrases::english::greetings::hello; +use phrases::english::farewells::goodbye; + +fn main() { + println!("Hello in English: {}", hello()); + println!("Goodbye in English: {}", goodbye()); +} +``` + +But it is not idiomatic. This is significantly more likely to introduce a +naming conflict. In our short program, it's not a big deal, but as it grows, it +becomes a problem. If we have conflicting names, Rust will give a compilation +error. For example, if we made the `japanese` functions public, and tried to do +this: + +```{rust,ignore} +extern crate phrases; + +use phrases::english::greetings::hello; +use phrases::japanese::greetings::hello; + +fn main() { + println!("Hello in English: {}", hello()); + println!("Hello in Japanese: {}", hello()); +} +``` + +Rust will give us a compile-time error: + +```text + Compiling phrases v0.0.1 (file:///home/you/projects/phrases) +src/main.rs:4:5: 4:40 error: a value named `hello` has already been imported in this module [E0252] +src/main.rs:4 use phrases::japanese::greetings::hello; + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +error: aborting due to previous error +Could not compile `phrases`. +``` + +If we're importing multiple names from the same module, we don't have to type it out +twice. Instead of this: + +```{rust,ignore} +use phrases::english::greetings; +use phrases::english::farewells; +``` + +We can use this shortcut: + +```{rust,ignore} +use phrases::english::{greetings, farewells}; +``` + +## Re-exporting with `pub use` + +You don't just use `use` to shorten identifiers. You can also use it inside of your crate +to re-export a function inside another module. This allows you to present an external +interface that may not directly map to your internal code organization. + +Let's look at an example. Modify your `src/main.rs` to read like this: + +```{rust,ignore} +extern crate phrases; + +use phrases::english::{greetings,farewells}; +use phrases::japanese; + +fn main() { + println!("Hello in English: {}", greetings::hello()); + println!("Goodbye in English: {}", farewells::goodbye()); + + println!("Hello in Japanese: {}", japanese::hello()); + println!("Goodbye in Japanese: {}", japanese::goodbye()); +} +``` + +Then, modify your `src/lib.rs` to make the `japanese` mod public: + +```{rust,ignore} +pub mod english; +pub mod japanese; +``` + +Next, make the two functions public, first in `src/japanese/greetings.rs`: + +```{rust,ignore} +pub fn hello() -> String { + "こんにちは".to_string() +} +``` + +And then in `src/japanese/farewells.rs`: + +```{rust,ignore} +pub fn goodbye() -> String { + "さようなら".to_string() +} +``` + +Finally, modify your `src/japanese/mod.rs` to read like this: + +```{rust,ignore} +pub use self::greetings::hello; +pub use self::farewells::goodbye; + +mod greetings; +mod farewells; +``` + +The `pub use` declaration brings the function into scope at this part of our +module hierarchy. Because we've `pub use`d this inside of our `japanese` +module, we now have a `phrases::japanese::hello()` function and a +`phrases::japanese::goodbye()` function, even though the code for them lives in +`phrases::japanese::greetings::hello()` and +`phrases::japanese::farewells::goodbye()`. Our internal organization doesn't +define our external interface. + +Here we have a `pub use` for each function we want to bring into the +`japanese` scope. We could alternatively use the wildcard syntax to include +everything from `greetings` into the current scope: `pub use self::greetings::*`. + +What about the `self`? Well, by default, `use` declarations are absolute paths, +starting from your crate root. `self` makes that path relative to your current +place in the hierarchy instead. There's one more special form of `use`: you can +`use super::` to reach one level up the tree from your current location. Some +people like to think of `self` as `.` and `super` as `..`, from many shells' +display for the current directory and the parent directory. + +Outside of `use`, paths are relative: `foo::bar()` refers to a function inside +of `foo` relative to where we are. If that's prefixed with `::`, as in +`::foo::bar()`, it refers to a different `foo`, an absolute path from your +crate root. + +Also, note that we `pub use`d before we declared our `mod`s. Rust requires that +`use` declarations go first. + +This will build and run: + +```bash +$ cargo run + Compiling phrases v0.0.1 (file:///home/you/projects/phrases) + Running `target/debug/phrases` +Hello in English: Hello! +Goodbye in English: Goodbye. +Hello in Japanese: こんにちは +Goodbye in Japanese: さようなら +``` diff --git a/src/doc/trpl/debug-and-display.md b/src/doc/trpl/debug-and-display.md index e69de29bb2d1d..6c8d788b5ae3b 100644 --- a/src/doc/trpl/debug-and-display.md +++ b/src/doc/trpl/debug-and-display.md @@ -0,0 +1,3 @@ +% `Debug` and `Display` + +Coming soon! diff --git a/src/doc/trpl/deref-coercions.md b/src/doc/trpl/deref-coercions.md index e69de29bb2d1d..afacd30405521 100644 --- a/src/doc/trpl/deref-coercions.md +++ b/src/doc/trpl/deref-coercions.md @@ -0,0 +1,3 @@ +% `Deref` coercions + +Coming soon! diff --git a/src/doc/trpl/documentation.md b/src/doc/trpl/documentation.md index e69de29bb2d1d..06071a8f15fa4 100644 --- a/src/doc/trpl/documentation.md +++ b/src/doc/trpl/documentation.md @@ -0,0 +1,562 @@ +% Documentation + +Documentation is an important part of any software project, and it's +first-class in Rust. Let's talk about the tooling Rust gives you to +document your project. + +## About `rustdoc` + +The Rust distribution includes a tool, `rustdoc`, that generates documentation. +`rustdoc` is also used by Cargo through `cargo doc`. + +Documentation can be generated in two ways: from source code, and from +standalone Markdown files. + +## Documenting source code + +The primary way of documenting a Rust project is through annotating the source +code. You can use documentation comments for this purpose: + +```rust,ignore +/// Constructs a new `Rc`. +/// +/// # Examples +/// +/// ``` +/// use std::rc::Rc; +/// +/// let five = Rc::new(5); +/// ``` +pub fn new(value: T) -> Rc { + // implementation goes here +} +``` + +This code generates documentation that looks [like this][rc-new]. I've left the +implementation out, with a regular comment in its place. That's the first thing +to notice about this annotation: it uses `///`, instead of `//`. The triple slash +indicates a documentation comment. + +Documentation comments are written in Markdown. + +Rust keeps track of these comments, and uses them when generating +documentation. This is important when documenting things like enums: + +``` +/// The `Option` type. See [the module level documentation](../) for more. +enum Option { + /// No value + None, + /// Some value `T` + Some(T), +} +``` + +The above works, but this does not: + +```rust,ignore +/// The `Option` type. See [the module level documentation](../) for more. +enum Option { + None, /// No value + Some(T), /// Some value `T` +} +``` + +You'll get an error: + +```text +hello.rs:4:1: 4:2 error: expected ident, found `}` +hello.rs:4 } + ^ +``` + +This [unfortunate error](https://github.com/rust-lang/rust/issues/22547) is +correct: documentation comments apply to the thing after them, and there's no +thing after that last comment. + +[rc-new]: http://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new + +### Writing documentation comments + +Anyway, let's cover each part of this comment in detail: + +``` +/// Constructs a new `Rc`. +# fn foo() {} +``` + +The first line of a documentation comment should be a short summary of its +functionality. One sentence. Just the basics. High level. + +``` +/// +/// Other details about constructing `Rc`s, maybe describing complicated +/// semantics, maybe additional options, all kinds of stuff. +/// +# fn foo() {} +``` + +Our original example had just a summary line, but if we had more things to say, +we could have added more explanation in a new paragraph. + +#### Special sections + +``` +/// # Examples +# fn foo() {} +``` + +Next, are special sections. These are indicated with a header, `#`. There +are three kinds of headers that are commonly used. They aren't special syntax, +just convention, for now. + +``` +/// # Panics +# fn foo() {} +``` + +Unrecoverable misuses of a function (i.e. programming errors) in Rust are +usually indicated by panics, which kill the whole current thread at the very +least. If your function has a non-trivial contract like this, that is +detected/enforced by panics, documenting it is very important. + +``` +/// # Failures +# fn foo() {} +``` + +If your function or method returns a `Result`, then describing the +conditions under which it returns `Err(E)` is a nice thing to do. This is +slightly less important than `Panics`, because failure is encoded into the type +system, but it's still a good thing to do. + +``` +/// # Safety +# fn foo() {} +``` + +If your function is `unsafe`, you should explain which invariants the caller is +responsible for upholding. + +``` +/// # Examples +/// +/// ``` +/// use std::rc::Rc; +/// +/// let five = Rc::new(5); +/// ``` +# fn foo() {} +``` + +Third, `Examples`. Include one or more examples of using your function or +method, and your users will love you for it. These examples go inside of +code block annotations, which we'll talk about in a moment, and can have +more than one section: + +``` +/// # Examples +/// +/// Simple `&str` patterns: +/// +/// ``` +/// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect(); +/// assert_eq!(v, vec!["Mary", "had", "a", "little", "lamb"]); +/// ``` +/// +/// More complex patterns with a lambda: +/// +/// ``` +/// let v: Vec<&str> = "abc1def2ghi".split(|c: char| c.is_numeric()).collect(); +/// assert_eq!(v, vec!["abc", "def", "ghi"]); +/// ``` +# fn foo() {} +``` + +Let's discuss the details of these code blocks. + +#### Code block annotations + +To write some Rust code in a comment, use the triple graves: + +``` +/// ``` +/// println!("Hello, world"); +/// ``` +# fn foo() {} +``` + +If you want something that's not Rust code, you can add an annotation: + +``` +/// ```c +/// printf("Hello, world\n"); +/// ``` +# fn foo() {} +``` + +This will highlight according to whatever language you're showing off. +If you're just showing plain text, choose `text`. + +It's important to choose the correct annotation here, because `rustdoc` uses it +in an interesting way: It can be used to actually test your examples, so that +they don't get out of date. If you have some C code but `rustdoc` thinks it's +Rust because you left off the annotation, `rustdoc` will complain when trying to +generate the documentation. + +## Documentation as tests + +Let's discuss our sample example documentation: + +``` +/// ``` +/// println!("Hello, world"); +/// ``` +# fn foo() {} +``` + +You'll notice that you don't need a `fn main()` or anything here. `rustdoc` will +automatically add a main() wrapper around your code, and in the right place. +For example: + +``` +/// ``` +/// use std::rc::Rc; +/// +/// let five = Rc::new(5); +/// ``` +# fn foo() {} +``` + +This will end up testing: + +``` +fn main() { + use std::rc::Rc; + let five = Rc::new(5); +} +``` + +Here's the full algorithm rustdoc uses to postprocess examples: + +1. Any leading `#![foo]` attributes are left intact as crate attributes. +2. Some common `allow` attributes are inserted, including + `unused_variables`, `unused_assignments`, `unused_mut`, + `unused_attributes`, and `dead_code`. Small examples often trigger + these lints. +3. If the example does not contain `extern crate`, then `extern crate + ;` is inserted. +2. Finally, if the example does not contain `fn main`, the remainder of the + text is wrapped in `fn main() { your_code }` + +Sometimes, this isn't enough, though. For example, all of these code samples +with `///` we've been talking about? The raw text: + +```text +/// Some documentation. +# fn foo() {} +``` + +looks different than the output: + +``` +/// Some documentation. +# fn foo() {} +``` + +Yes, that's right: you can add lines that start with `# `, and they will +be hidden from the output, but will be used when compiling your code. You +can use this to your advantage. In this case, documentation comments need +to apply to some kind of function, so if I want to show you just a +documentation comment, I need to add a little function definition below +it. At the same time, it's just there to satisfy the compiler, so hiding +it makes the example more clear. You can use this technique to explain +longer examples in detail, while still preserving the testability of your +documentation. For example, this code: + +``` +let x = 5; +let y = 6; +println!("{}", x + y); +``` + +Here's an explanation, rendered: + +First, we set `x` to five: + +``` +let x = 5; +# let y = 6; +# println!("{}", x + y); +``` + +Next, we set `y` to six: + +``` +# let x = 5; +let y = 6; +# println!("{}", x + y); +``` + +Finally, we print the sum of `x` and `y`: + +``` +# let x = 5; +# let y = 6; +println!("{}", x + y); +``` + +Here's the same explanation, in raw text: + +> First, we set `x` to five: +> +> ```text +> let x = 5; +> # let y = 6; +> # println!("{}", x + y); +> ``` +> +> Next, we set `y` to six: +> +> ```text +> # let x = 5; +> let y = 6; +> # println!("{}", x + y); +> ``` +> +> Finally, we print the sum of `x` and `y`: +> +> ```text +> # let x = 5; +> # let y = 6; +> println!("{}", x + y); +> ``` + +By repeating all parts of the example, you can ensure that your example still +compiles, while only showing the parts that are relevant to that part of your +explanation. + +### Documenting macros + +Here’s an example of documenting a macro: + +``` +/// Panic with a given message unless an expression evaluates to true. +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate foo; +/// # fn main() { +/// panic_unless!(1 + 1 == 2, “Math is broken.”); +/// # } +/// ``` +/// +/// ```should_panic +/// # #[macro_use] extern crate foo; +/// # fn main() { +/// panic_unless!(true == false, “I’m broken.”); +/// # } +/// ``` +#[macro_export] +macro_rules! panic_unless { + ($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } }); +} +# fn main() {} +``` + +You’ll note three things: we need to add our own `extern crate` line, so that +we can add the `#[macro_use]` attribute. Second, we’ll need to add our own +`main()` as well. Finally, a judicious use of `#` to comment out those two +things, so they don’t show up in the output. + +### Running documentation tests + +To run the tests, either + +```bash +$ rustdoc --test path/to/my/crate/root.rs +# or +$ cargo test +``` + +That's right, `cargo test` tests embedded documentation too. + +There are a few more annotations that are useful to help `rustdoc` do the right +thing when testing your code: + +``` +/// ```ignore +/// fn foo() { +/// ``` +# fn foo() {} +``` + +The `ignore` directive tells Rust to ignore your code. This is almost never +what you want, as it's the most generic. Instead, consider annotating it +with `text` if it's not code, or using `#`s to get a working example that +only shows the part you care about. + +``` +/// ```should_panic +/// assert!(false); +/// ``` +# fn foo() {} +``` + +`should_panic` tells `rustdoc` that the code should compile correctly, but +not actually pass as a test. + +``` +/// ```no_run +/// loop { +/// println!("Hello, world"); +/// } +/// ``` +# fn foo() {} +``` + +The `no_run` attribute will compile your code, but not run it. This is +important for examples such as "Here's how to start up a network service," +which you would want to make sure compile, but might run in an infinite loop! + +### Documenting modules + +Rust has another kind of doc comment, `//!`. This comment doesn't document the next item, but the enclosing item. In other words: + +``` +mod foo { + //! This is documentation for the `foo` module. + //! + //! # Examples + + // ... +} +``` + +This is where you'll see `//!` used most often: for module documentation. If +you have a module in `foo.rs`, you'll often open its code and see this: + +``` +//! A module for using `foo`s. +//! +//! The `foo` module contains a lot of useful functionality blah blah blah +``` + +### Documentation comment style + +Check out [RFC 505][rfc505] for full conventions around the style and format of +documentation. + +[rfc505]: https://github.com/rust-lang/rfcs/blob/master/text/0505-api-comment-conventions.md + +## Other documentation + +All of this behavior works in non-Rust source files too. Because comments +are written in Markdown, they're often `.md` files. + +When you write documentation in Markdown files, you don't need to prefix +the documentation with comments. For example: + +``` +/// # Examples +/// +/// ``` +/// use std::rc::Rc; +/// +/// let five = Rc::new(5); +/// ``` +# fn foo() {} +``` + +is just + +~~~markdown +# Examples + +``` +use std::rc::Rc; + +let five = Rc::new(5); +``` +~~~ + +when it's in a Markdown file. There is one wrinkle though: Markdown files need +to have a title like this: + +```markdown +% The title + +This is the example documentation. +``` + +This `%` line needs to be the very first line of the file. + +## `doc` attributes + +At a deeper level, documentation comments are sugar for documentation attributes: + +``` +/// this +# fn foo() {} + +#[doc="this"] +# fn bar() {} +``` + +are the same, as are these: + +``` +//! this + +#![doc="/// this"] +``` + +You won't often see this attribute used for writing documentation, but it +can be useful when changing some options, or when writing a macro. + +### Re-exports + +`rustdoc` will show the documentation for a public re-export in both places: + +```ignore +extern crate foo; + +pub use foo::bar; +``` + +This will create documentation for bar both inside the documentation for the +crate `foo`, as well as the documentation for your crate. It will use the same +documentation in both places. + +This behavior can be suppressed with `no_inline`: + +```ignore +extern crate foo; + +#[doc(no_inline)] +pub use foo::bar; +``` + +### Controlling HTML + +You can control a few aspects of the HTML that `rustdoc` generates through the +`#![doc]` version of the attribute: + +``` +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://doc.rust-lang.org/")]; +``` + +This sets a few different options, with a logo, favicon, and a root URL. + +## Generation options + +`rustdoc` also contains a few other options on the command line, for further customiziation: + +- `--html-in-header FILE`: includes the contents of FILE at the end of the + `...` section. +- `--html-before-content FILE`: includes the contents of FILE directly after + ``, before the rendered content (including the search bar). +- `--html-after-content FILE`: includes the contents of FILE after all the rendered content. diff --git a/src/doc/trpl/drop.md b/src/doc/trpl/drop.md index e69de29bb2d1d..af58e23561c36 100644 --- a/src/doc/trpl/drop.md +++ b/src/doc/trpl/drop.md @@ -0,0 +1,3 @@ +% `Drop` + +Coming soon! diff --git a/src/doc/trpl/effective-rust.md b/src/doc/trpl/effective-rust.md index e69de29bb2d1d..6ea0759e99d7b 100644 --- a/src/doc/trpl/effective-rust.md +++ b/src/doc/trpl/effective-rust.md @@ -0,0 +1 @@ +% Effective Rust diff --git a/src/doc/trpl/enums.md b/src/doc/trpl/enums.md index e69de29bb2d1d..cbb74d97c3555 100644 --- a/src/doc/trpl/enums.md +++ b/src/doc/trpl/enums.md @@ -0,0 +1,149 @@ +% Enums + +Finally, Rust has a "sum type", an *enum*. Enums are an incredibly useful +feature of Rust, and are used throughout the standard library. An `enum` is +a type which relates a set of alternates to a specific name. For example, below +we define `Character` to be either a `Digit` or something else. These +can be used via their fully scoped names: `Character::Other` (more about `::` +below). + +```rust +enum Character { + Digit(i32), + Other, +} +``` + +Most normal types are allowed as the variant components of an `enum`. Here are +some examples: + +```rust +struct Empty; +struct Color(i32, i32, i32); +struct Length(i32); +struct Status { Health: i32, Mana: i32, Attack: i32, Defense: i32 } +struct HeightDatabase(Vec); +``` + +You see that, depending on its type, an `enum` variant may or may not hold data. +In `Character`, for instance, `Digit` gives a meaningful name for an `i32` +value, where `Other` is only a name. However, the fact that they represent +distinct categories of `Character` is a very useful property. + +As with structures, the variants of an enum by default are not comparable with +equality operators (`==`, `!=`), have no ordering (`<`, `>=`, etc.), and do not +support other binary operations such as `*` and `+`. As such, the following code +is invalid for the example `Character` type: + +```{rust,ignore} +// These assignments both succeed +let ten = Character::Digit(10); +let four = Character::Digit(4); + +// Error: `*` is not implemented for type `Character` +let forty = ten * four; + +// Error: `<=` is not implemented for type `Character` +let four_is_smaller = four <= ten; + +// Error: `==` is not implemented for type `Character` +let four_equals_ten = four == ten; +``` + +This may seem rather limiting, but it's a limitation which we can overcome. +There are two ways: by implementing equality ourselves, or by pattern matching +variants with [`match`][match] expressions, which you'll learn in the next +chapter. We don't know enough about Rust to implement equality yet, but we can +use the `Ordering` enum from the standard library, which does: + +``` +enum Ordering { + Less, + Equal, + Greater, +} +``` + +Because `Ordering` has already been defined for us, we will import it with the +`use` keyword. Here's an example of how it is used: + +```{rust} +use std::cmp::Ordering; + +fn cmp(a: i32, b: i32) -> Ordering { + if a < b { Ordering::Less } + else if a > b { Ordering::Greater } + else { Ordering::Equal } +} + +fn main() { + let x = 5; + let y = 10; + + let ordering = cmp(x, y); // ordering: Ordering + + if ordering == Ordering::Less { + println!("less"); + } else if ordering == Ordering::Greater { + println!("greater"); + } else if ordering == Ordering::Equal { + println!("equal"); + } +} +``` + +The `::` symbol is used to indicate a namespace. In this case, `Ordering` lives +in the `cmp` submodule of the `std` module. We'll talk more about modules later +in the guide. For now, all you need to know is that you can `use` things from +the standard library if you need them. + +Okay, let's talk about the actual code in the example. `cmp` is a function that +compares two things, and returns an `Ordering`. We return either +`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on +whether the first value is less than, greater than, or equal to the second. Note +that each variant of the `enum` is namespaced under the `enum` itself: it's +`Ordering::Greater`, not `Greater`. + +The `ordering` variable has the type `Ordering`, and so contains one of the +three values. We then do a bunch of `if`/`else` comparisons to check which +one it is. + +This `Ordering::Greater` notation is too long. Let's use another form of `use` +to import the `enum` variants instead. This will avoid full scoping: + +```{rust} +use std::cmp::Ordering::{self, Equal, Less, Greater}; + +fn cmp(a: i32, b: i32) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} + +fn main() { + let x = 5; + let y = 10; + + let ordering = cmp(x, y); // ordering: Ordering + + if ordering == Less { println!("less"); } + else if ordering == Greater { println!("greater"); } + else if ordering == Equal { println!("equal"); } +} +``` + +Importing variants is convenient and compact, but can also cause name conflicts, +so do this with caution. For this reason, it's normally considered better style +to `use` an enum rather than its variants directly. + +As you can see, `enum`s are quite a powerful tool for data representation, and +are even more useful when they're [generic][generics] across types. Before we +get to generics, though, let's talk about how to use enums with pattern +matching, a tool that will let us deconstruct sum types (the type theory term +for enums) like `Ordering` in a very elegant way that avoids all these messy +and brittle `if`/`else`s. + + +[arity]: ./glossary.html#arity +[match]: ./match.html +[generics]: ./generics.html diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index e69de29bb2d1d..b9e7bd78c5b2f 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -0,0 +1,301 @@ +% Error Handling + +> The best-laid plans of mice and men +> Often go awry +> +> "Tae a Moose", Robert Burns + +Sometimes, things just go wrong. It's important to have a plan for when the +inevitable happens. Rust has rich support for handling errors that may (let's +be honest: will) occur in your programs. + +There are two main kinds of errors that can occur in your programs: failures, +and panics. Let's talk about the difference between the two, and then discuss +how to handle each. Then, we'll discuss upgrading failures to panics. + +# Failure vs. Panic + +Rust uses two terms to differentiate between two forms of error: failure, and +panic. A *failure* is an error that can be recovered from in some way. A +*panic* is an error that cannot be recovered from. + +What do we mean by "recover"? Well, in most cases, the possibility of an error +is expected. For example, consider the `from_str` function: + +```{rust,ignore} +from_str("5"); +``` + +This function takes a string argument and converts it into another type. But +because it's a string, you can't be sure that the conversion actually works. +For example, what should this convert to? + +```{rust,ignore} +from_str("hello5world"); +``` + +This won't work. So we know that this function will only work properly for some +inputs. It's expected behavior. We call this kind of error a *failure*. + +On the other hand, sometimes, there are errors that are unexpected, or which +we cannot recover from. A classic example is an `assert!`: + +```{rust,ignore} +assert!(x == 5); +``` + +We use `assert!` to declare that something is true. If it's not true, something +is very wrong. Wrong enough that we can't continue with things in the current +state. Another example is using the `unreachable!()` macro: + +```{rust,ignore} +enum Event { + NewRelease, +} + +fn probability(_: &Event) -> f64 { + // real implementation would be more complex, of course + 0.95 +} + +fn descriptive_probability(event: Event) -> &'static str { + match probability(&event) { + 1.00 => "certain", + 0.00 => "impossible", + 0.00 ... 0.25 => "very unlikely", + 0.25 ... 0.50 => "unlikely", + 0.50 ... 0.75 => "likely", + 0.75 ... 1.00 => "very likely", + } +} + +fn main() { + std::io::println(descriptive_probability(NewRelease)); +} +``` + +This will give us an error: + +```text +error: non-exhaustive patterns: `_` not covered [E0004] +``` + +While we know that we've covered all possible cases, Rust can't tell. It +doesn't know that probability is between 0.0 and 1.0. So we add another case: + +```rust +use Event::NewRelease; + +enum Event { + NewRelease, +} + +fn probability(_: &Event) -> f64 { + // real implementation would be more complex, of course + 0.95 +} + +fn descriptive_probability(event: Event) -> &'static str { + match probability(&event) { + 1.00 => "certain", + 0.00 => "impossible", + 0.00 ... 0.25 => "very unlikely", + 0.25 ... 0.50 => "unlikely", + 0.50 ... 0.75 => "likely", + 0.75 ... 1.00 => "very likely", + _ => unreachable!() + } +} + +fn main() { + println!("{}", descriptive_probability(NewRelease)); +} +``` + +We shouldn't ever hit the `_` case, so we use the `unreachable!()` macro to +indicate this. `unreachable!()` gives a different kind of error than `Result`. +Rust calls these sorts of errors *panics*. + +# Handling errors with `Option` and `Result` + +The simplest way to indicate that a function may fail is to use the `Option` +type. Remember our `from_str()` example? Here's its type signature: + +```{rust,ignore} +pub fn from_str(s: &str) -> Option +``` + +`from_str()` returns an `Option`. If the conversion succeeds, it will return +`Some(value)`, and if it fails, it will return `None`. + +This is appropriate for the simplest of cases, but doesn't give us a lot of +information in the failure case. What if we wanted to know _why_ the conversion +failed? For this, we can use the `Result` type. It looks like this: + +```rust +enum Result { + Ok(T), + Err(E) +} +``` + +This enum is provided by Rust itself, so you don't need to define it to use it +in your code. The `Ok(T)` variant represents a success, and the `Err(E)` variant +represents a failure. Returning a `Result` instead of an `Option` is recommended +for all but the most trivial of situations. + +Here's an example of using `Result`: + +```rust +#[derive(Debug)] +enum Version { Version1, Version2 } + +#[derive(Debug)] +enum ParseError { InvalidHeaderLength, InvalidVersion } + +fn parse_version(header: &[u8]) -> Result { + if header.len() < 1 { + return Err(ParseError::InvalidHeaderLength); + } + match header[0] { + 1 => Ok(Version::Version1), + 2 => Ok(Version::Version2), + _ => Err(ParseError::InvalidVersion) + } +} + +let version = parse_version(&[1, 2, 3, 4]); +match version { + Ok(v) => { + println!("working with version: {:?}", v); + } + Err(e) => { + println!("error parsing header: {:?}", e); + } +} +``` + +This function makes use of an enum, `ParseError`, to enumerate the various +errors that can occur. + +# Non-recoverable errors with `panic!` + +In the case of an error that is unexpected and not recoverable, the `panic!` +macro will induce a panic. This will crash the current thread, and give an error: + +```{rust,ignore} +panic!("boom"); +``` + +gives + +```text +thread '
' panicked at 'boom', hello.rs:2 +``` + +when you run it. + +Because these kinds of situations are relatively rare, use panics sparingly. + +# Upgrading failures to panics + +In certain circumstances, even though a function may fail, we may want to treat +it as a panic instead. For example, `io::stdin().read_line(&mut buffer)` returns +an `Result`, when there is an error reading the line. This allows us to +handle and possibly recover from error. + +If we don't want to handle this error, and would rather just abort the program, +we can use the `unwrap()` method: + +```{rust,ignore} +io::stdin().read_line(&mut buffer).unwrap(); +``` + +`unwrap()` will `panic!` if the `Option` is `None`. This basically says "Give +me the value, and if something goes wrong, just crash." This is less reliable +than matching the error and attempting to recover, but is also significantly +shorter. Sometimes, just crashing is appropriate. + +There's another way of doing this that's a bit nicer than `unwrap()`: + +```{rust,ignore} +let mut buffer = String::new(); +let input = io::stdin().read_line(&mut buffer) + .ok() + .expect("Failed to read line"); +``` + +`ok()` converts the `Result` into an `Option`, and `expect()` does the same +thing as `unwrap()`, but takes a message. This message is passed along to the +underlying `panic!`, providing a better error message if the code errors. + +# Using `try!` + +When writing code that calls many functions that return the `Result` type, the +error handling can be tedious. The `try!` macro hides some of the boilerplate +of propagating errors up the call stack. + +It replaces this: + +```rust +use std::fs::File; +use std::io; +use std::io::prelude::*; + +struct Info { + name: String, + age: i32, + rating: i32, +} + +fn write_info(info: &Info) -> io::Result<()> { + let mut file = File::open("my_best_friends.txt").unwrap(); + + if let Err(e) = writeln!(&mut file, "name: {}", info.name) { + return Err(e) + } + if let Err(e) = writeln!(&mut file, "age: {}", info.age) { + return Err(e) + } + if let Err(e) = writeln!(&mut file, "rating: {}", info.rating) { + return Err(e) + } + + return Ok(()); +} +``` + +With this: + +```rust +use std::fs::File; +use std::io; +use std::io::prelude::*; + +struct Info { + name: String, + age: i32, + rating: i32, +} + +fn write_info(info: &Info) -> io::Result<()> { + let mut file = try!(File::open("my_best_friends.txt")); + + try!(writeln!(&mut file, "name: {}", info.name)); + try!(writeln!(&mut file, "age: {}", info.age)); + try!(writeln!(&mut file, "rating: {}", info.rating)); + + return Ok(()); +} +``` + +Wrapping an expression in `try!` will result in the unwrapped success (`Ok`) +value, unless the result is `Err`, in which case `Err` is returned early from +the enclosing function. + +It's worth noting that you can only use `try!` from a function that returns a +`Result`, which means that you cannot use `try!` inside of `main()`, because +`main()` doesn't return anything. + +`try!` makes use of [`FromError`](../std/error/#the-fromerror-trait) to determine +what to return in the error case. diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index e69de29bb2d1d..23f6e17b860b2 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -0,0 +1,530 @@ +% Foreign Function Interface + +# Introduction + +This guide will use the [snappy](https://github.com/google/snappy) +compression/decompression library as an introduction to writing bindings for +foreign code. Rust is currently unable to call directly into a C++ library, but +snappy includes a C interface (documented in +[`snappy-c.h`](https://github.com/google/snappy/blob/master/snappy-c.h)). + +The following is a minimal example of calling a foreign function which will +compile if snappy is installed: + +```no_run +# #![feature(libc)] +extern crate libc; +use libc::size_t; + +#[link(name = "snappy")] +extern { + fn snappy_max_compressed_length(source_length: size_t) -> size_t; +} + +fn main() { + let x = unsafe { snappy_max_compressed_length(100) }; + println!("max compressed length of a 100 byte buffer: {}", x); +} +``` + +The `extern` block is a list of function signatures in a foreign library, in +this case with the platform's C ABI. The `#[link(...)]` attribute is used to +instruct the linker to link against the snappy library so the symbols are +resolved. + +Foreign functions are assumed to be unsafe so calls to them need to be wrapped +with `unsafe {}` as a promise to the compiler that everything contained within +truly is safe. C libraries often expose interfaces that aren't thread-safe, and +almost any function that takes a pointer argument isn't valid for all possible +inputs since the pointer could be dangling, and raw pointers fall outside of +Rust's safe memory model. + +When declaring the argument types to a foreign function, the Rust compiler can +not check if the declaration is correct, so specifying it correctly is part of +keeping the binding correct at runtime. + +The `extern` block can be extended to cover the entire snappy API: + +```no_run +# #![feature(libc)] +extern crate libc; +use libc::{c_int, size_t}; + +#[link(name = "snappy")] +extern { + fn snappy_compress(input: *const u8, + input_length: size_t, + compressed: *mut u8, + compressed_length: *mut size_t) -> c_int; + fn snappy_uncompress(compressed: *const u8, + compressed_length: size_t, + uncompressed: *mut u8, + uncompressed_length: *mut size_t) -> c_int; + fn snappy_max_compressed_length(source_length: size_t) -> size_t; + fn snappy_uncompressed_length(compressed: *const u8, + compressed_length: size_t, + result: *mut size_t) -> c_int; + fn snappy_validate_compressed_buffer(compressed: *const u8, + compressed_length: size_t) -> c_int; +} +# fn main() {} +``` + +# Creating a safe interface + +The raw C API needs to be wrapped to provide memory safety and make use of higher-level concepts +like vectors. A library can choose to expose only the safe, high-level interface and hide the unsafe +internal details. + +Wrapping the functions which expect buffers involves using the `slice::raw` module to manipulate Rust +vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous block of memory. The +length is number of elements currently contained, and the capacity is the total size in elements of +the allocated memory. The length is less than or equal to the capacity. + +``` +# #![feature(libc)] +# extern crate libc; +# use libc::{c_int, size_t}; +# unsafe fn snappy_validate_compressed_buffer(_: *const u8, _: size_t) -> c_int { 0 } +# fn main() {} +pub fn validate_compressed_buffer(src: &[u8]) -> bool { + unsafe { + snappy_validate_compressed_buffer(src.as_ptr(), src.len() as size_t) == 0 + } +} +``` + +The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, but it makes the +guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function +signature. + +The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be +allocated to hold the output too. + +The `snappy_max_compressed_length` function can be used to allocate a vector with the maximum +required capacity to hold the compressed output. The vector can then be passed to the +`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve +the true length after compression for setting the length. + +``` +# #![feature(libc)] +# extern crate libc; +# use libc::{size_t, c_int}; +# unsafe fn snappy_compress(a: *const u8, b: size_t, c: *mut u8, +# d: *mut size_t) -> c_int { 0 } +# unsafe fn snappy_max_compressed_length(a: size_t) -> size_t { a } +# fn main() {} +pub fn compress(src: &[u8]) -> Vec { + unsafe { + let srclen = src.len() as size_t; + let psrc = src.as_ptr(); + + let mut dstlen = snappy_max_compressed_length(srclen); + let mut dst = Vec::with_capacity(dstlen as usize); + let pdst = dst.as_mut_ptr(); + + snappy_compress(psrc, srclen, pdst, &mut dstlen); + dst.set_len(dstlen as usize); + dst + } +} +``` + +Decompression is similar, because snappy stores the uncompressed size as part of the compression +format and `snappy_uncompressed_length` will retrieve the exact buffer size required. + +``` +# #![feature(libc)] +# extern crate libc; +# use libc::{size_t, c_int}; +# unsafe fn snappy_uncompress(compressed: *const u8, +# compressed_length: size_t, +# uncompressed: *mut u8, +# uncompressed_length: *mut size_t) -> c_int { 0 } +# unsafe fn snappy_uncompressed_length(compressed: *const u8, +# compressed_length: size_t, +# result: *mut size_t) -> c_int { 0 } +# fn main() {} +pub fn uncompress(src: &[u8]) -> Option> { + unsafe { + let srclen = src.len() as size_t; + let psrc = src.as_ptr(); + + let mut dstlen: size_t = 0; + snappy_uncompressed_length(psrc, srclen, &mut dstlen); + + let mut dst = Vec::with_capacity(dstlen as usize); + let pdst = dst.as_mut_ptr(); + + if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 { + dst.set_len(dstlen as usize); + Some(dst) + } else { + None // SNAPPY_INVALID_INPUT + } + } +} +``` + +For reference, the examples used here are also available as an [library on +GitHub](https://github.com/thestinger/rust-snappy). + +# Destructors + +Foreign libraries often hand off ownership of resources to the calling code. +When this occurs, we must use Rust's destructors to provide safety and guarantee +the release of these resources (especially in the case of panic). + +For more about destructors, see the [Drop trait](../std/ops/trait.Drop.html). + +# Callbacks from C code to Rust functions + +Some external libraries require the usage of callbacks to report back their +current state or intermediate data to the caller. +It is possible to pass functions defined in Rust to an external library. +The requirement for this is that the callback function is marked as `extern` +with the correct calling convention to make it callable from C code. + +The callback function can then be sent through a registration call +to the C library and afterwards be invoked from there. + +A basic example is: + +Rust code: + +```no_run +extern fn callback(a: i32) { + println!("I'm called from C with value {0}", a); +} + +#[link(name = "extlib")] +extern { + fn register_callback(cb: extern fn(i32)) -> i32; + fn trigger_callback(); +} + +fn main() { + unsafe { + register_callback(callback); + trigger_callback(); // Triggers the callback + } +} +``` + +C code: + +```c +typedef void (*rust_callback)(int32_t); +rust_callback cb; + +int32_t register_callback(rust_callback callback) { + cb = callback; + return 1; +} + +void trigger_callback() { + cb(7); // Will call callback(7) in Rust +} +``` + +In this example Rust's `main()` will call `trigger_callback()` in C, +which would, in turn, call back to `callback()` in Rust. + + +## Targeting callbacks to Rust objects + +The former example showed how a global function can be called from C code. +However it is often desired that the callback is targeted to a special +Rust object. This could be the object that represents the wrapper for the +respective C object. + +This can be achieved by passing an unsafe pointer to the object down to the +C library. The C library can then include the pointer to the Rust object in +the notification. This will allow the callback to unsafely access the +referenced Rust object. + +Rust code: + +```no_run +#[repr(C)] +struct RustObject { + a: i32, + // other members +} + +extern "C" fn callback(target: *mut RustObject, a: i32) { + println!("I'm called from C with value {0}", a); + unsafe { + // Update the value in RustObject with the value received from the callback + (*target).a = a; + } +} + +#[link(name = "extlib")] +extern { + fn register_callback(target: *mut RustObject, + cb: extern fn(*mut RustObject, i32)) -> i32; + fn trigger_callback(); +} + +fn main() { + // Create the object that will be referenced in the callback + let mut rust_object = Box::new(RustObject { a: 5 }); + + unsafe { + register_callback(&mut *rust_object, callback); + trigger_callback(); + } +} +``` + +C code: + +```c +typedef void (*rust_callback)(void*, int32_t); +void* cb_target; +rust_callback cb; + +int32_t register_callback(void* callback_target, rust_callback callback) { + cb_target = callback_target; + cb = callback; + return 1; +} + +void trigger_callback() { + cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust +} +``` + +## Asynchronous callbacks + +In the previously given examples the callbacks are invoked as a direct reaction +to a function call to the external C library. +The control over the current thread is switched from Rust to C to Rust for the +execution of the callback, but in the end the callback is executed on the +same thread that called the function which triggered the callback. + +Things get more complicated when the external library spawns its own threads +and invokes callbacks from there. +In these cases access to Rust data structures inside the callbacks is +especially unsafe and proper synchronization mechanisms must be used. +Besides classical synchronization mechanisms like mutexes, one possibility in +Rust is to use channels (in `std::comm`) to forward data from the C thread +that invoked the callback into a Rust thread. + +If an asynchronous callback targets a special object in the Rust address space +it is also absolutely necessary that no more callbacks are performed by the +C library after the respective Rust object gets destroyed. +This can be achieved by unregistering the callback in the object's +destructor and designing the library in a way that guarantees that no +callback will be performed after deregistration. + +# Linking + +The `link` attribute on `extern` blocks provides the basic building block for +instructing rustc how it will link to native libraries. There are two accepted +forms of the link attribute today: + +* `#[link(name = "foo")]` +* `#[link(name = "foo", kind = "bar")]` + +In both of these cases, `foo` is the name of the native library that we're +linking to, and in the second case `bar` is the type of native library that the +compiler is linking to. There are currently three known types of native +libraries: + +* Dynamic - `#[link(name = "readline")]` +* Static - `#[link(name = "my_build_dependency", kind = "static")]` +* Frameworks - `#[link(name = "CoreFoundation", kind = "framework")]` + +Note that frameworks are only available on OSX targets. + +The different `kind` values are meant to differentiate how the native library +participates in linkage. From a linkage perspective, the rust compiler creates +two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary). +Native dynamic libraries and frameworks are propagated to the final artifact +boundary, while static libraries are not propagated at all. + +A few examples of how this model can be used are: + +* A native build dependency. Sometimes some C/C++ glue is needed when writing + some rust code, but distribution of the C/C++ code in a library format is just + a burden. In this case, the code will be archived into `libfoo.a` and then the + rust crate would declare a dependency via `#[link(name = "foo", kind = + "static")]`. + + Regardless of the flavor of output for the crate, the native static library + will be included in the output, meaning that distribution of the native static + library is not necessary. + +* A normal dynamic dependency. Common system libraries (like `readline`) are + available on a large number of systems, and often a static copy of these + libraries cannot be found. When this dependency is included in a rust crate, + partial targets (like rlibs) will not link to the library, but when the rlib + is included in a final target (like a binary), the native library will be + linked in. + +On OSX, frameworks behave with the same semantics as a dynamic library. + +# Unsafe blocks + +Some operations, like dereferencing unsafe pointers or calling functions that have been marked +unsafe are only allowed inside unsafe blocks. Unsafe blocks isolate unsafety and are a promise to +the compiler that the unsafety does not leak out of the block. + +Unsafe functions, on the other hand, advertise it to the world. An unsafe function is written like +this: + +``` +unsafe fn kaboom(ptr: *const i32) -> i32 { *ptr } +``` + +This function can only be called from an `unsafe` block or another `unsafe` function. + +# Accessing foreign globals + +Foreign APIs often export a global variable which could do something like track +global state. In order to access these variables, you declare them in `extern` +blocks with the `static` keyword: + +```no_run +# #![feature(libc)] +extern crate libc; + +#[link(name = "readline")] +extern { + static rl_readline_version: libc::c_int; +} + +fn main() { + println!("You have readline version {} installed.", + rl_readline_version as i32); +} +``` + +Alternatively, you may need to alter global state provided by a foreign +interface. To do this, statics can be declared with `mut` so we can mutate +them. + +```no_run +# #![feature(libc)] +extern crate libc; + +use std::ffi::CString; +use std::ptr; + +#[link(name = "readline")] +extern { + static mut rl_prompt: *const libc::c_char; +} + +fn main() { + let prompt = CString::new("[my-awesome-shell] $").unwrap(); + unsafe { + rl_prompt = prompt.as_ptr(); + + println!("{:?}", rl_prompt); + + rl_prompt = ptr::null(); + } +} +``` + +Note that all interaction with a `static mut` is unsafe, both reading and +writing. Dealing with global mutable state requires a great deal of care. + +# Foreign calling conventions + +Most foreign code exposes a C ABI, and Rust uses the platform's C calling convention by default when +calling foreign functions. Some foreign functions, most notably the Windows API, use other calling +conventions. Rust provides a way to tell the compiler which convention to use: + +``` +# #![feature(libc)] +extern crate libc; + +#[cfg(all(target_os = "win32", target_arch = "x86"))] +#[link(name = "kernel32")] +#[allow(non_snake_case)] +extern "stdcall" { + fn SetEnvironmentVariableA(n: *const u8, v: *const u8) -> libc::c_int; +} +# fn main() { } +``` + +This applies to the entire `extern` block. The list of supported ABI constraints +are: + +* `stdcall` +* `aapcs` +* `cdecl` +* `fastcall` +* `Rust` +* `rust-intrinsic` +* `system` +* `C` +* `win64` + +Most of the abis in this list are self-explanatory, but the `system` abi may +seem a little odd. This constraint selects whatever the appropriate ABI is for +interoperating with the target's libraries. For example, on win32 with a x86 +architecture, this means that the abi used would be `stdcall`. On x86_64, +however, windows uses the `C` calling convention, so `C` would be used. This +means that in our previous example, we could have used `extern "system" { ... }` +to define a block for all windows systems, not just x86 ones. + +# Interoperability with foreign code + +Rust guarantees that the layout of a `struct` is compatible with the platform's +representation in C only if the `#[repr(C)]` attribute is applied to it. +`#[repr(C, packed)]` can be used to lay out struct members without padding. +`#[repr(C)]` can also be applied to an enum. + +Rust's owned boxes (`Box`) use non-nullable pointers as handles which point +to the contained object. However, they should not be manually created because +they are managed by internal allocators. References can safely be assumed to be +non-nullable pointers directly to the type. However, breaking the borrow +checking or mutability rules is not guaranteed to be safe, so prefer using raw +pointers (`*`) if that's needed because the compiler can't make as many +assumptions about them. + +Vectors and strings share the same basic memory layout, and utilities are +available in the `vec` and `str` modules for working with C APIs. However, +strings are not terminated with `\0`. If you need a NUL-terminated string for +interoperability with C, you should use the `CString` type in the `std::ffi` +module. + +The standard library includes type aliases and function definitions for the C +standard library in the `libc` module, and Rust links against `libc` and `libm` +by default. + +# The "nullable pointer optimization" + +Certain types are defined to not be `null`. This includes references (`&T`, +`&mut T`), boxes (`Box`), and function pointers (`extern "abi" fn()`). +When interfacing with C, pointers that might be null are often used. +As a special case, a generic `enum` that contains exactly two variants, one of +which contains no data and the other containing a single field, is eligible +for the "nullable pointer optimization". When such an enum is instantiated +with one of the non-nullable types, it is represented as a single pointer, +and the non-data variant is represented as the null pointer. So +`Option c_int>` is how one represents a nullable +function pointer using the C ABI. + +# Calling Rust code from C + +You may wish to compile Rust code in a way so that it can be called from C. This is +fairly easy, but requires a few things: + +``` +#[no_mangle] +pub extern fn hello_rust() -> *const u8 { + "Hello, world!\0".as_ptr() +} +# fn main() {} +``` + +The `extern` makes this function adhere to the C calling convention, as +discussed above in "[Foreign Calling +Conventions](ffi.html#foreign-calling-conventions)". The `no_mangle` +attribute turns off Rust's name mangling, so that it is easier to link to. diff --git a/src/doc/trpl/for-loops.md b/src/doc/trpl/for-loops.md index e69de29bb2d1d..45ae5a2e2dd9a 100644 --- a/src/doc/trpl/for-loops.md +++ b/src/doc/trpl/for-loops.md @@ -0,0 +1,44 @@ +% `for` Loops + +The `for` loop is used to loop a particular number of times. Rust's `for` loops +work a bit differently than in other systems languages, however. Rust's `for` +loop doesn't look like this "C-style" `for` loop: + +```{c} +for (x = 0; x < 10; x++) { + printf( "%d\n", x ); +} +``` + +Instead, it looks like this: + +```{rust} +for x in 0..10 { + println!("{}", x); // x: i32 +} +``` + +In slightly more abstract terms, + +```{ignore} +for var in expression { + code +} +``` + +The expression is an iterator, which we will discuss in more depth later in the +guide. The iterator gives back a series of elements. Each element is one +iteration of the loop. That value is then bound to the name `var`, which is +valid for the loop body. Once the body is over, the next value is fetched from +the iterator, and we loop another time. When there are no more values, the +`for` loop is over. + +In our example, `0..10` is an expression that takes a start and an end position, +and gives an iterator over those values. The upper bound is exclusive, though, +so our loop will print `0` through `9`, not `10`. + +Rust does not have the "C-style" `for` loop on purpose. Manually controlling +each element of the loop is complicated and error prone, even for experienced C +developers. + +We'll talk more about `for` when we cover *iterators*, later in the Guide. diff --git a/src/doc/trpl/functions.md b/src/doc/trpl/functions.md index e69de29bb2d1d..8e8ee8d63d626 100644 --- a/src/doc/trpl/functions.md +++ b/src/doc/trpl/functions.md @@ -0,0 +1,193 @@ +% Functions + +You've already seen one function so far, the `main` function: + +```rust +fn main() { +} +``` + +This is the simplest possible function declaration. As we mentioned before, +`fn` says "this is a function," followed by the name, some parentheses because +this function takes no arguments, and then some curly braces to indicate the +body. Here's a function named `foo`: + +```rust +fn foo() { +} +``` + +So, what about taking arguments? Here's a function that prints a number: + +```rust +fn print_number(x: i32) { + println!("x is: {}", x); +} +``` + +Here's a complete program that uses `print_number`: + +```rust +fn main() { + print_number(5); +} + +fn print_number(x: i32) { + println!("x is: {}", x); +} +``` + +As you can see, function arguments work very similar to `let` declarations: +you add a type to the argument name, after a colon. + +Here's a complete program that adds two numbers together and prints them: + +```rust +fn main() { + print_sum(5, 6); +} + +fn print_sum(x: i32, y: i32) { + println!("sum is: {}", x + y); +} +``` + +You separate arguments with a comma, both when you call the function, as well +as when you declare it. + +Unlike `let`, you _must_ declare the types of function arguments. This does +not work: + +```{rust,ignore} +fn print_sum(x, y) { + println!("sum is: {}", x + y); +} +``` + +You get this error: + +```text +hello.rs:5:18: 5:19 expected one of `!`, `:`, or `@`, found `)` +hello.rs:5 fn print_number(x, y) { +``` + +This is a deliberate design decision. While full-program inference is possible, +languages which have it, like Haskell, often suggest that documenting your +types explicitly is a best-practice. We agree that forcing functions to declare +types while allowing for inference inside of function bodies is a wonderful +sweet spot between full inference and no inference. + +What about returning a value? Here's a function that adds one to an integer: + +```rust +fn add_one(x: i32) -> i32 { + x + 1 +} +``` + +Rust functions return exactly one value, and you declare the type after an +"arrow," which is a dash (`-`) followed by a greater-than sign (`>`). + +You'll note the lack of a semicolon here. If we added it in: + +```{rust,ignore} +fn add_one(x: i32) -> i32 { + x + 1; +} +``` + +We would get an error: + +```text +error: not all control paths return a value +fn add_one(x: i32) -> i32 { + x + 1; +} + +help: consider removing this semicolon: + x + 1; + ^ +``` + +Remember our earlier discussions about semicolons and `()`? Our function claims +to return an `i32`, but with a semicolon, it would return `()` instead. Rust +realizes this probably isn't what we want, and suggests removing the semicolon. + +This is very much like our `if` statement before: the result of the block +(`{}`) is the value of the expression. Other expression-oriented languages, +such as Ruby, work like this, but it's a bit unusual in the systems programming +world. When people first learn about this, they usually assume that it +introduces bugs. But because Rust's type system is so strong, and because unit +is its own unique type, we have never seen an issue where adding or removing a +semicolon in a return position would cause a bug. + +But what about early returns? Rust does have a keyword for that, `return`: + +```rust +fn foo(x: i32) -> i32 { + if x < 5 { return x; } + + x + 1 +} +``` + +Using a `return` as the last line of a function works, but is considered poor +style: + +```rust +fn foo(x: i32) -> i32 { + if x < 5 { return x; } + + return x + 1; +} +``` + +The previous definition without `return` may look a bit strange if you haven't +worked in an expression-based language before, but it becomes intuitive over +time. If this were production code, we wouldn't write it in that way anyway, +we'd write this: + +```rust +fn foo(x: i32) -> i32 { + if x < 5 { + x + } else { + x + 1 + } +} +``` + +Because `if` is an expression, and it's the only expression in this function, +the value will be the result of the `if`. + +## Diverging functions + +Rust has some special syntax for 'diverging functions', which are functions that +do not return: + +``` +fn diverges() -> ! { + panic!("This function never returns!"); +} +``` + +`panic!` is a macro, similar to `println!()` that we've already seen. Unlike +`println!()`, `panic!()` causes the current thread of execution to crash with +the given message. + +Because this function will cause a crash, it will never return, and so it has +the type '`!`', which is read "diverges." A diverging function can be used +as any type: + +```should_panic +# fn diverges() -> ! { +# panic!("This function never returns!"); +# } + +let x: i32 = diverges(); +let x: String = diverges(); +``` + +We don't have a good use for diverging functions yet, because they're used in +conjunction with other Rust features. But when you see `-> !` later, you'll +know what it's called. diff --git a/src/doc/trpl/generics.md b/src/doc/trpl/generics.md index e69de29bb2d1d..3e4e0a66eae05 100644 --- a/src/doc/trpl/generics.md +++ b/src/doc/trpl/generics.md @@ -0,0 +1,177 @@ +% Generics + +Sometimes, when writing a function or data type, we may want it to work for +multiple types of arguments. For example, remember our `OptionalInt` type? + +```{rust} +enum OptionalInt { + Value(i32), + Missing, +} +``` + +If we wanted to also have an `OptionalFloat64`, we would need a new enum: + +```{rust} +enum OptionalFloat64 { + Valuef64(f64), + Missingf64, +} +``` + +This is really unfortunate. Luckily, Rust has a feature that gives us a better +way: generics. Generics are called *parametric polymorphism* in type theory, +which means that they are types or functions that have multiple forms (*poly* +is multiple, *morph* is form) over a given parameter (*parametric*). + +Anyway, enough with type theory declarations, let's check out the generic form +of `OptionalInt`. It is actually provided by Rust itself, and looks like this: + +```rust +enum Option { + Some(T), + None, +} +``` + +The `` part, which you've seen a few times before, indicates that this is +a generic data type. Inside the declaration of our enum, wherever we see a `T`, +we substitute that type for the same type used in the generic. Here's an +example of using `Option`, with some extra type annotations: + +```{rust} +let x: Option = Some(5); +``` + +In the type declaration, we say `Option`. Note how similar this looks to +`Option`. So, in this particular `Option`, `T` has the value of `i32`. On +the right-hand side of the binding, we do make a `Some(T)`, where `T` is `5`. +Since that's an `i32`, the two sides match, and Rust is happy. If they didn't +match, we'd get an error: + +```{rust,ignore} +let x: Option = Some(5); +// error: mismatched types: expected `core::option::Option`, +// found `core::option::Option<_>` (expected f64 but found integral variable) +``` + +That doesn't mean we can't make `Option`s that hold an `f64`! They just have to +match up: + +```{rust} +let x: Option = Some(5); +let y: Option = Some(5.0f64); +``` + +This is just fine. One definition, multiple uses. + +Generics don't have to only be generic over one type. Consider Rust's built-in +`Result` type: + +```{rust} +enum Result { + Ok(T), + Err(E), +} +``` + +This type is generic over _two_ types: `T` and `E`. By the way, the capital letters +can be any letter you'd like. We could define `Result` as: + +```{rust} +enum Result { + Ok(A), + Err(Z), +} +``` + +if we wanted to. Convention says that the first generic parameter should be +`T`, for 'type,' and that we use `E` for 'error.' Rust doesn't care, however. + +The `Result` type is intended to be used to return the result of a +computation, and to have the ability to return an error if it didn't work out. +Here's an example: + +```{rust} +let x: Result = Ok(2.3f64); +let y: Result = Err("There was an error.".to_string()); +``` + +This particular Result will return an `f64` if there's a success, and a +`String` if there's a failure. Let's write a function that uses `Result`: + +```{rust} +fn inverse(x: f64) -> Result { + if x == 0.0f64 { return Err("x cannot be zero!".to_string()); } + + Ok(1.0f64 / x) +} +``` + +We don't want to take the inverse of zero, so we check to make sure that we +weren't passed zero. If we were, then we return an `Err`, with a message. If +it's okay, we return an `Ok`, with the answer. + +Why does this matter? Well, remember how `match` does exhaustive matches? +Here's how this function gets used: + +```{rust} +# fn inverse(x: f64) -> Result { +# if x == 0.0f64 { return Err("x cannot be zero!".to_string()); } +# Ok(1.0f64 / x) +# } +let x = inverse(25.0f64); + +match x { + Ok(x) => println!("The inverse of 25 is {}", x), + Err(msg) => println!("Error: {}", msg), +} +``` + +The `match` enforces that we handle the `Err` case. In addition, because the +answer is wrapped up in an `Ok`, we can't just use the result without doing +the match: + +```{rust,ignore} +let x = inverse(25.0f64); +println!("{}", x + 2.0f64); // error: binary operation `+` cannot be applied + // to type `core::result::Result` +``` + +This function is great, but there's one other problem: it only works for 64 bit +floating point values. What if we wanted to handle 32 bit floating point as +well? We'd have to write this: + +```{rust} +fn inverse32(x: f32) -> Result { + if x == 0.0f32 { return Err("x cannot be zero!".to_string()); } + + Ok(1.0f32 / x) +} +``` + +Bummer. What we need is a *generic function*. Luckily, we can write one! +However, it won't _quite_ work yet. Before we get into that, let's talk syntax. +A generic version of `inverse` would look something like this: + +```{rust,ignore} +fn inverse(x: T) -> Result { + if x == 0.0 { return Err("x cannot be zero!".to_string()); } + + Ok(1.0 / x) +} +``` + +Just like how we had `Option`, we use a similar syntax for `inverse`. +We can then use `T` inside the rest of the signature: `x` has type `T`, and half +of the `Result` has type `T`. However, if we try to compile that example, we'll get +an error: + +```text +error: binary operation `==` cannot be applied to type `T` +``` + +Because `T` can be _any_ type, it may be a type that doesn't implement `==`, +and therefore, the first line would be wrong. What do we do? + +To fix this example, we need to learn about another Rust feature: traits. diff --git a/src/doc/trpl/getting-started.md b/src/doc/trpl/getting-started.md index e69de29bb2d1d..a164def516b93 100644 --- a/src/doc/trpl/getting-started.md +++ b/src/doc/trpl/getting-started.md @@ -0,0 +1 @@ +% Getting Started diff --git a/src/doc/trpl/glossary.md b/src/doc/trpl/glossary.md index e69de29bb2d1d..97898324847e4 100644 --- a/src/doc/trpl/glossary.md +++ b/src/doc/trpl/glossary.md @@ -0,0 +1,39 @@ +% Glossary + +Not every Rustacean has a background in systems programming, nor in computer +science, so we've added explanations of terms that might be unfamiliar. + +### Arity + +Arity refers to the number of arguments a function or operation takes. + +```rust +let x = (2, 3); +let y = (4, 6); +let z = (8, 2, 6); +``` + +In the example above `x` and `y` have arity 2. `z` has arity 3. + +### Abstract Syntax Tree + +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 +structure of your program. For example, `2 + 3` can be turned into a tree: + +```text + + + / \ +2 3 +``` + +And `2 + (3 * 4)` would look like this: + +```text + + + / \ +2 * + / \ + 3 4 +``` diff --git a/src/doc/trpl/hello-cargo.md b/src/doc/trpl/hello-cargo.md index e69de29bb2d1d..ae2a79bafecd5 100644 --- a/src/doc/trpl/hello-cargo.md +++ b/src/doc/trpl/hello-cargo.md @@ -0,0 +1,168 @@ +% Hello, Cargo! + +[Cargo](http://crates.io) is a tool that Rustaceans use to help manage their +Rust projects. Cargo is currently in a pre-1.0 state, just like Rust, and so it +is still a work in progress. However, it is already good enough to use for many +Rust projects, and so it is assumed that Rust projects will use Cargo from the +beginning. + +Cargo manages three things: building your code, downloading the dependencies +your code needs, and building those dependencies. At first, your +program doesn't have any dependencies, so we'll only be using the first part of +its functionality. Eventually, we'll add more. Since we started off by using +Cargo, it'll be easy to add later. + +If you installed Rust via the official installers you will also have +Cargo. If you installed Rust some other way, you may want to [check +the Cargo +README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies) +for specific instructions about installing it. + +## Converting to Cargo + +Let's convert Hello World to Cargo. + +To Cargo-ify our project, we need to do two things: Make a `Cargo.toml` +configuration file, and put our source file in the right place. Let's +do that part first: + +```bash +$ mkdir src +$ mv main.rs src/main.rs +``` + +Cargo expects your source files to live inside a `src` directory. That leaves +the top level for other things, like READMEs, license information, and anything +not related to your code. Cargo helps us keep our projects nice and tidy. A +place for everything, and everything in its place. + +Next, our configuration file: + +```bash +$ editor Cargo.toml +``` + +Make sure to get this name right: you need the capital `C`! + +Put this inside: + +```toml +[package] + +name = "hello_world" +version = "0.0.1" +authors = [ "Your name " ] + +[[bin]] + +name = "hello_world" +``` + +This file is in the [TOML](https://github.com/toml-lang/toml) format. Let's let +it explain itself to you: + +> TOML aims to be a minimal configuration file format that's easy to read due +> to obvious semantics. TOML is designed to map unambiguously to a hash table. +> TOML should be easy to parse into data structures in a wide variety of +> languages. + +TOML is very similar to INI, but with some extra goodies. + +Anyway, there are two *tables* in this file: `package` and `bin`. The first +tells Cargo metadata about your package. The second tells Cargo that we're +interested in building a binary, not a library (though we could do both!), as +well as what it is named. + +Once you have this file in place, we should be ready to build! Try this: + +```bash +$ cargo build + Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world) +$ ./target/debug/hello_world +Hello, world! +``` + +Bam! We build our project with `cargo build`, and run it with +`./target/debug/hello_world`. This hasn't bought us a whole lot over our simple use +of `rustc`, but think about the future: when our project has more than one +file, we would need to call `rustc` more than once and pass it a bunch of options to +tell it to build everything together. With Cargo, as our project grows, we can +just `cargo build`, and it'll work the right way. When your project is finally +ready for release, you can use `cargo build --release` to compile your crates with +optimizations. + +You'll also notice that Cargo has created a new file: `Cargo.lock`. + +```toml +[root] +name = "hello_world" +version = "0.0.1" +``` + +This file is used by Cargo to keep track of dependencies in your application. +Right now, we don't have any, so it's a bit sparse. You won't ever need +to touch this file yourself, just let Cargo handle it. + +That's it! We've successfully built `hello_world` with Cargo. Even though our +program is simple, it's using much of the real tooling that you'll use for the +rest of your Rust career. + +## A New Project + +You don't have to go through this whole process every time you want to start a new +project! Cargo has the ability to make a bare-bones project directory in which you +can start developing right away. + +To start a new project with Cargo, use `cargo new`: + +```bash +$ cargo new hello_world --bin +``` + +We're passing `--bin` because we're making a binary program: if we +were making a library, we'd leave it off. + +Let's check out what Cargo has generated for us: + +```bash +$ cd hello_world +$ tree . +. +├── Cargo.toml +└── src + └── main.rs + +1 directory, 2 files +``` + +If you don't have the `tree` command, you can probably get it from your distro's package +manager. It's not necessary, but it's certainly useful. + +This is all we need to get started. First, let's check out `Cargo.toml`: + +```toml +[package] + +name = "hello_world" +version = "0.0.1" +authors = ["Your Name "] +``` + +Cargo has populated this file with reasonable defaults based off the arguments you gave +it and your `git` global configuration. You may notice that Cargo has also initialized +the `hello_world` directory as a `git` repository. + +Here's what's in `src/main.rs`: + +```rust +fn main() { + println!("Hello, world!"); +} +``` + +Cargo has generated a "Hello World!" for us, and you're ready to start coding! A +much more in-depth guide to Cargo can be found [here](http://doc.crates.io/guide.html). + +Now that you've got the tools down, let's actually learn more about the Rust +language itself. These are the basics that will serve you well through the rest +of your time with Rust. diff --git a/src/doc/trpl/hello-world.md b/src/doc/trpl/hello-world.md index e69de29bb2d1d..f726f8627c929 100644 --- a/src/doc/trpl/hello-world.md +++ b/src/doc/trpl/hello-world.md @@ -0,0 +1,164 @@ +% Hello, world! + +Now that you have Rust installed, let's write your first Rust program. It's +traditional to make your first program in any new language one that prints the +text "Hello, world!" to the screen. The nice thing about starting with such a +simple program is that you can verify that your compiler isn't just installed, +but also working properly. And printing information to the screen is a pretty +common thing to do. + +The first thing that we need to do is make a file to put our code in. I like +to make a `projects` directory in my home directory, and keep all my projects +there. Rust does not care where your code lives. + +This actually leads to one other concern we should address: this guide will +assume that you have basic familiarity with the command line. Rust does not +require that you know a whole ton about the command line, but until the +language is in a more finished state, IDE support is spotty. Rust makes no +specific demands on your editing tooling, or where your code lives. + +With that said, let's make a directory in our projects directory. + +```{bash} +$ mkdir ~/projects +$ cd ~/projects +$ mkdir hello_world +$ cd hello_world +``` + +If you're on Windows and not using PowerShell, the `~` may not work. Consult +the documentation for your shell for more details. + +Let's make a new source file next. I'm going to use the syntax `editor +filename` to represent editing a file in these examples, but you should use +whatever method you want. We'll call our file `main.rs`: + +```{bash} +$ editor main.rs +``` + +Rust files always end in a `.rs` extension. If you're using more than one word +in your filename, use an underscore. `hello_world.rs` rather than +`helloworld.rs`. + +Now that you've got your file open, type this in: + +```{rust} +fn main() { + println!("Hello, world!"); +} +``` + +Save the file, and then type this into your terminal window: + +```{bash} +$ rustc main.rs +$ ./main # or main.exe on Windows +Hello, world! +``` + +You can also run these examples on [play.rust-lang.org](http://play.rust-lang.org/) by clicking on the arrow that appears in the upper right of the example when you mouse over the code. + +Success! Let's go over what just happened in detail. + +```{rust} +fn main() { + +} +``` + +These lines define a *function* in Rust. The `main` function is special: +it's the beginning of every Rust program. The first line says "I'm declaring a +function named `main`, which takes no arguments and returns nothing." If there +were arguments, they would go inside the parentheses (`(` and `)`), and because +we aren't returning anything from this function, we can omit the return type +entirely. We'll get to it later. + +You'll also note that the function is wrapped in curly braces (`{` and `}`). +Rust requires these around all function bodies. It is also considered good +style to put the opening curly brace on the same line as the function +declaration, with one space in between. + +Next up is this line: + +```{rust} + println!("Hello, world!"); +``` + +This line does all of the work in our little program. There are a number of +details that are important here. The first is that it's indented with four +spaces, not tabs. Please configure your editor of choice to insert four spaces +with the tab key. We provide some [sample configurations for various +editors](https://github.com/rust-lang/rust/tree/master/src/etc/CONFIGS.md). + +The second point is the `println!()` part. This is calling a Rust *macro*, +which is how metaprogramming is done in Rust. If it were a function instead, it +would look like this: `println()`. For our purposes, we don't need to worry +about this difference. Just know that sometimes, you'll see a `!`, and that +means that you're calling a macro instead of a normal function. Rust implements +`println!` as a macro rather than a function for good reasons, but that's a +very advanced topic. You'll learn more when we talk about macros later. One +last thing to mention: Rust's macros are significantly different from C macros, +if you've used those. Don't be scared of using macros. We'll get to the details +eventually, you'll just have to trust us for now. + +Next, `"Hello, world!"` is a *string*. Strings are a surprisingly complicated +topic in a systems programming language, and this is a *statically allocated* +string. We will talk more about different kinds of allocation later. We pass +this string as an argument to `println!`, which prints the string to the +screen. Easy enough! + +Finally, the line ends with a semicolon (`;`). Rust is an *expression +oriented* language, which means that most things are expressions. The `;` is +used to indicate that this expression is over, and the next one is ready to +begin. Most lines of Rust code end with a `;`. We will cover this in-depth +later in the guide. + +Finally, actually *compiling* and *running* our program. We can compile +with our compiler, `rustc`, by passing it the name of our source file: + +```{bash} +$ rustc main.rs +``` + +This is similar to `gcc` or `clang`, if you come from a C or C++ background. Rust +will output a binary executable. You can see it with `ls`: + +```{bash} +$ ls +main main.rs +``` + +Or on Windows: + +```{bash} +$ dir +main.exe main.rs +``` + +There are now two files: our source code, with the `.rs` extension, and the +executable (`main.exe` on Windows, `main` everywhere else) + +```{bash} +$ ./main # or main.exe on Windows +``` + +This prints out our `Hello, world!` text to our terminal. + +If you come from a dynamically typed language like Ruby, Python, or JavaScript, +you may not be used to these two steps being separate. Rust is an +*ahead-of-time compiled language*, which means that you can compile a +program, give it to someone else, and they don't need to have Rust installed. +If you give someone a `.rb` or `.py` or `.js` file, they need to have a +Ruby/Python/JavaScript implementation installed, but you just need one command +to both compile and run your program. Everything is a tradeoff in language design, +and Rust has made its choice. + +Congratulations! You have officially written a Rust program. That makes you a +Rust programmer! Welcome. + +Next, I'd like to introduce you to another tool, Cargo, which is used to write +real-world Rust programs. Just using `rustc` is nice for simple things, but as +your project grows, you'll want something to help you manage all of the options +that it has, and to make it easy to share your code with other people and +projects. diff --git a/src/doc/trpl/if.md b/src/doc/trpl/if.md index e69de29bb2d1d..92f95341f8149 100644 --- a/src/doc/trpl/if.md +++ b/src/doc/trpl/if.md @@ -0,0 +1,157 @@ +% `if` + +Rust's take on `if` is not particularly complex, but it's much more like the +`if` you'll find in a dynamically typed language than in a more traditional +systems language. So let's talk about it, to make sure you grasp the nuances. + +`if` is a specific form of a more general concept, the *branch*. The name comes +from a branch in a tree: a decision point, where depending on a choice, +multiple paths can be taken. + +In the case of `if`, there is one choice that leads down two paths: + +```rust +let x = 5; + +if x == 5 { + println!("x is five!"); +} +``` + +If we changed the value of `x` to something else, this line would not print. +More specifically, if the expression after the `if` evaluates to `true`, then +the block is executed. If it's `false`, then it is not. + +If you want something to happen in the `false` case, use an `else`: + +```{rust} +let x = 5; + +if x == 5 { + println!("x is five!"); +} else { + println!("x is not five :("); +} +``` + +If there is more than one case, use an `else if`: + +```rust +let x = 5; + +if x == 5 { + println!("x is five!"); +} else if x == 6 { + println!("x is six!"); +} else { + println!("x is not five or six :("); +} +``` + +This is all pretty standard. However, you can also do this: + + +```{rust} +let x = 5; + +let y = if x == 5 { + 10 +} else { + 15 +}; // y: i32 +``` + +Which we can (and probably should) write like this: + +```{rust} +let x = 5; + +let y = if x == 5 { 10 } else { 15 }; // y: i32 +``` + +This reveals two interesting things about Rust: it is an expression-based +language, and semicolons are different from semicolons in other 'curly brace +and semicolon'-based languages. These two things are related. + +## Expressions vs. Statements + +Rust is primarily an expression based language. There are only two kinds of +statements, and everything else is an expression. + +So what's the difference? Expressions return a value, and statements do not. +In many languages, `if` is a statement, and therefore, `let x = if ...` would +make no sense. But in Rust, `if` is an expression, which means that it returns +a value. We can then use this value to initialize the binding. + +Speaking of which, bindings are a kind of the first of Rust's two statements. +The proper name is a *declaration statement*. So far, `let` is the only kind +of declaration statement we've seen. Let's talk about that some more. + +In some languages, variable bindings can be written as expressions, not just +statements. Like Ruby: + +```{ruby} +x = y = 5 +``` + +In Rust, however, using `let` to introduce a binding is _not_ an expression. The +following will produce a compile-time error: + +```{ignore} +let x = (let y = 5); // expected identifier, found keyword `let` +``` + +The compiler is telling us here that it was expecting to see the beginning of +an expression, and a `let` can only begin a statement, not an expression. + +Note that assigning to an already-bound variable (e.g. `y = 5`) is still an +expression, although its value is not particularly useful. Unlike C, where an +assignment evaluates to the assigned value (e.g. `5` in the previous example), +in Rust the value of an assignment is the unit type `()` (which we'll cover later). + +The second kind of statement in Rust is the *expression statement*. Its +purpose is to turn any expression into a statement. In practical terms, Rust's +grammar expects statements to follow other statements. This means that you use +semicolons to separate expressions from each other. This means that Rust +looks a lot like most other languages that require you to use semicolons +at the end of every line, and you will see semicolons at the end of almost +every line of Rust code you see. + +What is this exception that makes us say "almost"? You saw it already, in this +code: + +```{rust} +let x = 5; + +let y: i32 = if x == 5 { 10 } else { 15 }; +``` + +Note that I've added the type annotation to `y`, to specify explicitly that I +want `y` to be an integer. + +This is not the same as this, which won't compile: + +```{ignore} +let x = 5; + +let y: i32 = if x == 5 { 10; } else { 15; }; +``` + +Note the semicolons after the 10 and 15. Rust will give us the following error: + +```text +error: mismatched types: expected `i32`, found `()` (expected i32, found ()) +``` + +We expected an integer, but we got `()`. `()` is pronounced *unit*, and is a +special type in Rust's type system. In Rust, `()` is _not_ a valid value for a +variable of type `i32`. It's only a valid value for variables of the type `()`, +which aren't very useful. Remember how we said statements don't return a value? +Well, that's the purpose of unit in this case. The semicolon turns any +expression into a statement by throwing away its value and returning unit +instead. + +There's one more time in which you won't see a semicolon at the end of a line +of Rust code. For that, we'll need our next concept: functions. + +TODO: `if let` diff --git a/src/doc/trpl/inline-assembly.md b/src/doc/trpl/inline-assembly.md index e69de29bb2d1d..1a4592f980fa7 100644 --- a/src/doc/trpl/inline-assembly.md +++ b/src/doc/trpl/inline-assembly.md @@ -0,0 +1,141 @@ +% Inline Assembly + +For extremely low-level manipulations and performance reasons, one +might wish to control the CPU directly. Rust supports using inline +assembly to do this via the `asm!` macro. The syntax roughly matches +that of GCC & Clang: + +```ignore +asm!(assembly template + : output operands + : input operands + : clobbers + : options + ); +``` + +Any use of `asm` is feature gated (requires `#![feature(asm)]` on the +crate to allow) and of course requires an `unsafe` block. + +> **Note**: the examples here are given in x86/x86-64 assembly, but +> all platforms are supported. + +## Assembly template + +The `assembly template` is the only required parameter and must be a +literal string (i.e. `""`) + +``` +#![feature(asm)] + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn foo() { + unsafe { + asm!("NOP"); + } +} + +// other platforms +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +fn foo() { /* ... */ } + +fn main() { + // ... + foo(); + // ... +} +``` + +(The `feature(asm)` and `#[cfg]`s are omitted from now on.) + +Output operands, input operands, clobbers and options are all optional +but you must add the right number of `:` if you skip them: + +``` +# #![feature(asm)] +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +# fn main() { unsafe { +asm!("xor %eax, %eax" + : + : + : "eax" + ); +# } } +``` + +Whitespace also doesn't matter: + +``` +# #![feature(asm)] +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +# fn main() { unsafe { +asm!("xor %eax, %eax" ::: "eax"); +# } } +``` + +## Operands + +Input and output operands follow the same format: `: +"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand +expressions must be mutable lvalues: + +``` +# #![feature(asm)] +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn add(a: i32, b: i32) -> i32 { + let mut c = 0; + unsafe { + asm!("add $2, $0" + : "=r"(c) + : "0"(a), "r"(b) + ); + } + c +} +# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +# fn add(a: i32, b: i32) -> i32 { a + b } + +fn main() { + assert_eq!(add(3, 14159), 14162) +} +``` + +## Clobbers + +Some instructions modify registers which might otherwise have held +different values so we use the clobbers list to indicate to the +compiler not to assume any values loaded into those registers will +stay valid. + +``` +# #![feature(asm)] +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +# fn main() { unsafe { +// Put the value 0x200 in eax +asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax"); +# } } +``` + +Input and output registers need not be listed since that information +is already communicated by the given constraints. Otherwise, any other +registers used either implicitly or explicitly should be listed. + +If the assembly changes the condition code register `cc` should be +specified as one of the clobbers. Similarly, if the assembly modifies +memory, `memory` should also be specified. + +## Options + +The last section, `options` is specific to Rust. The format is comma +separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to +specify some extra info about the inline assembly: + +Current valid options are: + +1. *volatile* - specifying this is analogous to + `__asm__ __volatile__ (...)` in gcc/clang. +2. *alignstack* - certain instructions expect the stack to be + aligned a certain way (i.e. SSE) and specifying this indicates to + the compiler to insert its usual stack alignment code +3. *intel* - use intel syntax instead of the default AT&T. + diff --git a/src/doc/trpl/installing-rust.md b/src/doc/trpl/installing-rust.md index e69de29bb2d1d..c839688047aa6 100644 --- a/src/doc/trpl/installing-rust.md +++ b/src/doc/trpl/installing-rust.md @@ -0,0 +1,93 @@ +% Installing Rust + +The first step to using Rust is to install it! There are a number of ways to +install Rust, but the easiest is to use the `rustup` script. If you're on +Linux or a Mac, all you need to do is this (note that you don't need to type +in the `$`s, they just indicate the start of each command): + +```bash +$ curl -sf -L https://static.rust-lang.org/rustup.sh | sudo sh +``` + +If you're concerned about the [potential insecurity](http://curlpipesh.tumblr.com/) of using `curl | sudo sh`, +please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script: + +```bash +$ curl -f -L https://static.rust-lang.org/rustup.sh -O +$ sudo sh rustup.sh +``` + +If you're on Windows, please download either the [32-bit +installer](https://static.rust-lang.org/dist/rust-1.0.0-beta-i686-pc-windows-gnu.exe) +or the [64-bit +installer](https://static.rust-lang.org/dist/rust-1.0.0-beta-x86_64-pc-windows-gnu.exe) +and run it. + +If you decide you don't want Rust anymore, we'll be a bit sad, but that's okay. +Not every programming language is great for everyone. Just run the uninstall +script: + +```bash +$ sudo /usr/local/lib/rustlib/uninstall.sh +``` + +If you used the Windows installer, just re-run the `.exe` and it will give you +an uninstall option. + +You can re-run this script any time you want to update Rust. Which, at this +point, is often. Rust is still pre-1.0, and so people assume that you're using +a very recent Rust. + +This brings me to one other point: some people, and somewhat rightfully so, get +very upset when we tell you to `curl | sudo sh`. And they should be! Basically, +when you do this, you are trusting that the good people who maintain Rust +aren't going to hack your computer and do bad things. That's a good instinct! +If you're one of those people, please check out the documentation on [building +Rust from Source](https://github.com/rust-lang/rust#building-from-source), or +[the official binary downloads](http://www.rust-lang.org/install.html). And we +promise that this method will not be the way to install Rust forever: it's just +the easiest way to keep people updated while Rust is in its alpha state. + +Oh, we should also mention the officially supported platforms: + +* Windows (7, 8, Server 2008 R2) +* Linux (2.6.18 or later, various distributions), x86 and x86-64 +* OSX 10.7 (Lion) or greater, x86 and x86-64 + +We extensively test Rust on these platforms, and a few others, too, like +Android. But these are the ones most likely to work, as they have the most +testing. + +Finally, a comment about Windows. Rust considers Windows to be a first-class +platform upon release, but if we're honest, the Windows experience isn't as +integrated as the Linux/OS X experience is. We're working on it! If anything +does not work, it is a bug. Please let us know if that happens. Each and every +commit is tested against Windows just like any other platform. + +If you've got Rust installed, you can open up a shell, and type this: + +```bash +$ rustc --version +``` + +You should see the version number, commit hash, commit date and build date: + +```bash +rustc 1.0.0-nightly (f11f3e7ba 2015-01-04) (built 2015-01-06) +``` + +If you did, Rust has been installed successfully! Congrats! + +This installer also installs a copy of the documentation locally, so you can +read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location. +On Windows, it's in a `share/doc` directory, inside wherever you installed Rust +to. + +If not, there are a number of places where you can get help. The easiest is +[the #rust IRC channel on irc.mozilla.org](irc://irc.mozilla.org/#rust), which +you can access through +[Mibbit](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust). Click +that link, and you'll be chatting with other Rustaceans (a silly nickname we +call ourselves), and we can help you out. Other great resources include [the +/r/rust subreddit](http://www.reddit.com/r/rust), and [Stack +Overflow](http://stackoverflow.com/questions/tagged/rust). diff --git a/src/doc/trpl/intrinsics.md b/src/doc/trpl/intrinsics.md index e69de29bb2d1d..25f7c54493188 100644 --- a/src/doc/trpl/intrinsics.md +++ b/src/doc/trpl/intrinsics.md @@ -0,0 +1,25 @@ +% Intrinsics + +> **Note**: intrinsics will forever have an unstable interface, it is +> recommended to use the stable interfaces of libcore rather than intrinsics +> directly. + +These are imported as if they were FFI functions, with the special +`rust-intrinsic` ABI. For example, if one was in a freestanding +context, but wished to be able to `transmute` between types, and +perform efficient pointer arithmetic, one would import those functions +via a declaration like + +``` +# #![feature(intrinsics)] +# fn main() {} + +extern "rust-intrinsic" { + fn transmute(x: T) -> U; + + fn offset(dst: *const T, offset: isize) -> *const T; +} +``` + +As with any other FFI functions, these are always `unsafe` to call. + diff --git a/src/doc/trpl/iterators.md b/src/doc/trpl/iterators.md index e69de29bb2d1d..eea575658b92c 100644 --- a/src/doc/trpl/iterators.md +++ b/src/doc/trpl/iterators.md @@ -0,0 +1,349 @@ +% Iterators + +Let's talk about loops. + +Remember Rust's `for` loop? Here's an example: + +```rust +for x in 0..10 { + println!("{}", x); +} +``` + +Now that you know more Rust, we can talk in detail about how this works. +Ranges (the `0..10`) are 'iterators'. An iterator is something that we can +call the `.next()` method on repeatedly, and it gives us a sequence of things. + +Like this: + +```rust +let mut range = 0..10; + +loop { + match range.next() { + Some(x) => { + println!("{}", x); + }, + None => { break } + } +} +``` + +We make a mutable binding to the range, which is our iterator. We then `loop`, +with an inner `match`. This `match` is used on the result of `range.next()`, +which gives us a reference to the next value of the iterator. `next` returns an +`Option`, in this case, which will be `Some(i32)` when we have a value and +`None` once we run out. If we get `Some(i32)`, we print it out, and if we get +`None`, we `break` out of the loop. + +This code sample is basically the same as our `for` loop version. The `for` +loop is just a handy way to write this `loop`/`match`/`break` construct. + +`for` loops aren't the only thing that uses iterators, however. Writing your +own iterator involves implementing the `Iterator` trait. While doing that is +outside of the scope of this guide, Rust provides a number of useful iterators +to accomplish various tasks. Before we talk about those, we should talk about a +Rust anti-pattern. And that's using ranges like this. + +Yes, we just talked about how ranges are cool. But ranges are also very +primitive. For example, if you needed to iterate over the contents of a vector, +you may be tempted to write this: + +```rust +let nums = vec![1, 2, 3]; + +for i in 0..nums.len() { + println!("{}", nums[i]); +} +``` + +This is strictly worse than using an actual iterator. You can iterate over vectors +directly, so write this: + +```rust +let nums = vec![1, 2, 3]; + +for num in &nums { + println!("{}", num); +} +``` + +There are two reasons for this. First, this more directly expresses what we +mean. We iterate through the entire vector, rather than iterating through +indexes, and then indexing the vector. Second, this version is more efficient: +the first version will have extra bounds checking because it used indexing, +`nums[i]`. But since we yield a reference to each element of the vector in turn +with the iterator, there's no bounds checking in the second example. This is +very common with iterators: we can ignore unnecessary bounds checks, but still +know that we're safe. + +There's another detail here that's not 100% clear because of how `println!` +works. `num` is actually of type `&i32`. That is, it's a reference to an `i32`, +not an `i32` itself. `println!` handles the dereferencing for us, so we don't +see it. This code works fine too: + +```rust +let nums = vec![1, 2, 3]; + +for num in &nums { + println!("{}", *num); +} +``` + +Now we're explicitly dereferencing `num`. Why does `&nums` give us +references? Firstly, because we explicitly asked it to with +`&`. Secondly, if it gave us the data itself, we would have to be its +owner, which would involve making a copy of the data and giving us the +copy. With references, we're just borrowing a reference to the data, +and so it's just passing a reference, without needing to do the move. + +So, now that we've established that ranges are often not what you want, let's +talk about what you do want instead. + +There are three broad classes of things that are relevant here: iterators, +*iterator adapters*, and *consumers*. Here's some definitions: + +* *iterators* give you a sequence of values. +* *iterator adapters* operate on an iterator, producing a new iterator with a + different output sequence. +* *consumers* operate on an iterator, producing some final set of values. + +Let's talk about consumers first, since you've already seen an iterator, ranges. + +## Consumers + +A *consumer* operates on an iterator, returning some kind of value or values. +The most common consumer is `collect()`. This code doesn't quite compile, +but it shows the intention: + +```{rust,ignore} +let one_to_one_hundred = (1..101).collect(); +``` + +As you can see, we call `collect()` on our iterator. `collect()` takes +as many values as the iterator will give it, and returns a collection +of the results. So why won't this compile? Rust can't determine what +type of things you want to collect, and so you need to let it know. +Here's the version that does compile: + +```rust +let one_to_one_hundred = (1..101).collect::>(); +``` + +If you remember, the `::<>` syntax allows us to give a type hint, +and so we tell it that we want a vector of integers. You don't always +need to use the whole type, though. Using a `_` will let you provide +a partial hint: + +```rust +let one_to_one_hundred = (1..101).collect::>(); +``` + +This says "Collect into a `Vec`, please, but infer what the `T` is for me." +`_` is sometimes called a "type placeholder" for this reason. + +`collect()` is the most common consumer, but there are others too. `find()` +is one: + +```rust +let greater_than_forty_two = (0..100) + .find(|x| *x > 42); + +match greater_than_forty_two { + Some(_) => println!("We got some numbers!"), + None => println!("No numbers found :("), +} +``` + +`find` takes a closure, and works on a reference to each element of an +iterator. This closure returns `true` if the element is the element we're +looking for, and `false` otherwise. Because we might not find a matching +element, `find` returns an `Option` rather than the element itself. + +Another important consumer is `fold`. Here's what it looks like: + +```rust +let sum = (1..4).fold(0, |sum, x| sum + x); +``` + +`fold()` is a consumer that looks like this: +`fold(base, |accumulator, element| ...)`. It takes two arguments: the first +is an element called the *base*. The second is a closure that itself takes two +arguments: the first is called the *accumulator*, and the second is an +*element*. Upon each iteration, the closure is called, and the result is the +value of the accumulator on the next iteration. On the first iteration, the +base is the value of the accumulator. + +Okay, that's a bit confusing. Let's examine the values of all of these things +in this iterator: + +| base | accumulator | element | closure result | +|------|-------------|---------|----------------| +| 0 | 0 | 1 | 1 | +| 0 | 1 | 2 | 3 | +| 0 | 3 | 3 | 6 | + +We called `fold()` with these arguments: + +```rust +# (1..4) +.fold(0, |sum, x| sum + x); +``` + +So, `0` is our base, `sum` is our accumulator, and `x` is our element. On the +first iteration, we set `sum` to `0`, and `x` is the first element of `nums`, +`1`. We then add `sum` and `x`, which gives us `0 + 1 = 1`. On the second +iteration, that value becomes our accumulator, `sum`, and the element is +the second element of the array, `2`. `1 + 2 = 3`, and so that becomes +the value of the accumulator for the last iteration. On that iteration, +`x` is the last element, `3`, and `3 + 3 = 6`, which is our final +result for our sum. `1 + 2 + 3 = 6`, and that's the result we got. + +Whew. `fold` can be a bit strange the first few times you see it, but once it +clicks, you can use it all over the place. Any time you have a list of things, +and you want a single result, `fold` is appropriate. + +Consumers are important due to one additional property of iterators we haven't +talked about yet: laziness. Let's talk some more about iterators, and you'll +see why consumers matter. + +## Iterators + +As we've said before, an iterator is something that we can call the +`.next()` method on repeatedly, and it gives us a sequence of things. +Because you need to call the method, this means that iterators +are *lazy* and don't need to generate all of the values upfront. +This code, for example, does not actually generate the numbers +`1-100`, and just creates a value that represents the sequence: + +```rust +let nums = 1..100; +``` + +Since we didn't do anything with the range, it didn't generate the sequence. +Let's add the consumer: + +```rust +let nums = (1..100).collect::>(); +``` + +Now, `collect()` will require that the range gives it some numbers, and so +it will do the work of generating the sequence. + +Ranges are one of two basic iterators that you'll see. The other is `iter()`. +`iter()` can turn a vector into a simple iterator that gives you each element +in turn: + +```rust +let nums = [1, 2, 3]; + +for num in nums.iter() { + println!("{}", num); +} +``` + +These two basic iterators should serve you well. There are some more +advanced iterators, including ones that are infinite. Like using range syntax +and `step_by`: + +```rust +# #![feature(step_by)] +(1..).step_by(5); +``` + +This iterator counts up from one, adding five each time. It will give +you a new integer every time, forever (well, technically, until it reaches the +maximum number representable by an `i32`). But since iterators are lazy, +that's okay! You probably don't want to use `collect()` on it, though... + +That's enough about iterators. Iterator adapters are the last concept +we need to talk about with regards to iterators. Let's get to it! + +## Iterator adapters + +*Iterator adapters* take an iterator and modify it somehow, producing +a new iterator. The simplest one is called `map`: + +```{rust,ignore} +(1..100).map(|x| x + 1); +``` + +`map` is called upon another iterator, and produces a new iterator where each +element reference has the closure it's been given as an argument called on it. +So this would give us the numbers from `2-100`. Well, almost! If you +compile the example, you'll get a warning: + +```text +warning: unused result which must be used: iterator adaptors are lazy and + do nothing unless consumed, #[warn(unused_must_use)] on by default +(1..100).map(|x| x + 1); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +Laziness strikes again! That closure will never execute. This example +doesn't print any numbers: + +```{rust,ignore} +(1..100).map(|x| println!("{}", x)); +``` + +If you are trying to execute a closure on an iterator for its side effects, +just use `for` instead. + +There are tons of interesting iterator adapters. `take(n)` will return an +iterator over the next `n` elements of the original iterator. Note that this +has no side effect on the original iterator. Let's try it out with our infinite +iterator from before: + +```rust +# #![feature(step_by)] +for i in (1..).step_by(5).take(5) { + println!("{}", i); +} +``` + +This will print + +```text +1 +6 +11 +16 +21 +``` + +`filter()` is an adapter that takes a closure as an argument. This closure +returns `true` or `false`. The new iterator `filter()` produces +only the elements that that closure returns `true` for: + +```rust +for i in (1..100).filter(|&x| x % 2 == 0) { + println!("{}", i); +} +``` + +This will print all of the even numbers between one and a hundred. +(Note that because `filter` doesn't consume the elements that are +being iterated over, it is passed a reference to each element, and +thus the filter predicate uses the `&x` pattern to extract the integer +itself.) + +You can chain all three things together: start with an iterator, adapt it +a few times, and then consume the result. Check it out: + +```rust +(1..1000) + .filter(|&x| x % 2 == 0) + .filter(|&x| x % 3 == 0) + .take(5) + .collect::>(); +``` + +This will give you a vector containing `6`, `12`, `18`, `24`, and `30`. + +This is just a small taste of what iterators, iterator adapters, and consumers +can help you with. There are a number of really useful iterators, and you can +write your own as well. Iterators provide a safe, efficient way to manipulate +all kinds of lists. They're a little unusual at first, but if you play with +them, you'll get hooked. For a full list of the different iterators and +consumers, check out the [iterator module documentation](../std/iter/index.html). diff --git a/src/doc/trpl/lang-items.md b/src/doc/trpl/lang-items.md index e69de29bb2d1d..5c27c03e8e0b2 100644 --- a/src/doc/trpl/lang-items.md +++ b/src/doc/trpl/lang-items.md @@ -0,0 +1,79 @@ +% Lang items + +> **Note**: lang items are often provided by crates in the Rust distribution, +> and lang items themselves have an unstable interface. It is recommended to use +> officially distributed crates instead of defining your own lang items. + +The `rustc` compiler has certain pluggable operations, that is, +functionality that isn't hard-coded into the language, but is +implemented in libraries, with a special marker to tell the compiler +it exists. The marker is the attribute `#[lang="..."]` and there are +various different values of `...`, i.e. various different 'lang +items'. + +For example, `Box` pointers require two lang items, one for allocation +and one for deallocation. A freestanding program that uses the `Box` +sugar for dynamic allocations via `malloc` and `free`: + +``` +#![feature(lang_items, box_syntax, start, no_std, libc)] +#![no_std] + +extern crate libc; + +extern { + fn abort() -> !; +} + +#[lang = "owned_box"] +pub struct Box(*mut T); + +#[lang="exchange_malloc"] +unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { + let p = libc::malloc(size as libc::size_t) as *mut u8; + + // malloc failed + if p as usize == 0 { + abort(); + } + + p +} +#[lang="exchange_free"] +unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) { + libc::free(ptr as *mut libc::c_void) +} + +#[start] +fn main(argc: isize, argv: *const *const u8) -> isize { + let x = box 1; + + 0 +} + +#[lang = "stack_exhausted"] extern fn stack_exhausted() {} +#[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +``` + +Note the use of `abort`: the `exchange_malloc` lang item is assumed to +return a valid pointer, and so needs to do the check internally. + +Other features provided by lang items include: + +- overloadable operators via traits: the traits corresponding to the + `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all + marked with lang items; those specific four are `eq`, `ord`, + `deref`, and `add` respectively. +- stack unwinding and general failure; the `eh_personality`, `fail` + and `fail_bounds_checks` lang items. +- the traits in `std::marker` used to indicate types of + various kinds; lang items `send`, `sync` and `copy`. +- the marker types and variance indicators found in + `std::marker`; lang items `covariant_type`, + `contravariant_lifetime`, etc. + +Lang items are loaded lazily by the compiler; e.g. if one never uses +`Box` then there is no need to define functions for `exchange_malloc` +and `exchange_free`. `rustc` will emit an error when an item is needed +but not found in the current crate or any that it depends on. diff --git a/src/doc/trpl/learn-rust.md b/src/doc/trpl/learn-rust.md index e69de29bb2d1d..e5482d3fb9681 100644 --- a/src/doc/trpl/learn-rust.md +++ b/src/doc/trpl/learn-rust.md @@ -0,0 +1 @@ +% Learn Rust diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md index e69de29bb2d1d..c6eee97dc6a61 100644 --- a/src/doc/trpl/lifetimes.md +++ b/src/doc/trpl/lifetimes.md @@ -0,0 +1,3 @@ +% Lifetimes + +Coming soon! diff --git a/src/doc/trpl/link-args.md b/src/doc/trpl/link-args.md index e69de29bb2d1d..ee5159afb8e6f 100644 --- a/src/doc/trpl/link-args.md +++ b/src/doc/trpl/link-args.md @@ -0,0 +1,25 @@ +% Link args + +There is one other way to tell rustc how to customize linking, and that is via +the `link_args` attribute. This attribute is applied to `extern` blocks and +specifies raw flags which need to get passed to the linker when producing an +artifact. An example usage would be: + +``` no_run +#![feature(link_args)] + +#[link_args = "-foo -bar -baz"] +extern {} +# fn main() {} +``` + +Note that this feature is currently hidden behind the `feature(link_args)` gate +because this is not a sanctioned way of performing linking. Right now rustc +shells out to the system linker, so it makes sense to provide extra command line +arguments, but this will not always be the case. In the future rustc may use +LLVM directly to link native libraries in which case `link_args` will have no +meaning. + +It is highly recommended to *not* use this attribute, and rather use the more +formal `#[link(...)]` attribute on `extern` blocks instead. + diff --git a/src/doc/trpl/lol.txt b/src/doc/trpl/lol.txt deleted file mode 100644 index ea7600113641b..0000000000000 --- a/src/doc/trpl/lol.txt +++ /dev/null @@ -1 +0,0 @@ -getting-started.md installing-rust.md hello-world.md hello-cargo.md learn-rust.md effective-rust.md the-stack-and-the-heap.md debug-and-display.md testing.md documentation.md iterators.md concurrency.md error-handling.md ffi.md deref-coercions.md syntax-and-semantics.md variable-bindings.md primitive-types.md functions.md comments.md structs.md mutability.md method-syntax.md enums.md if.md match.md patterns.md for-loops.md while-loops.md ownership.md references-and-borrowing.md lifetimes.md move-semantics.md drop.md vectors.md arrays.md slices.md strings.md traits.md operators-and-overloading.md generics.md trait-objects.md closures.md ufcs.md crates-and-modules.md static.md const.md tuples.md tuple-structs.md attributes.md conditional-compilation.md type-aliases.md casting-between-types.md associated-types.md unsized-types.md macros.md unsafe-code.md nightly-rust.md plugins.md inline-assembly.md no-stdlib.md intrinsics.md lang-items.md link-args.md benchmark-tests.md box-syntax-and-patterns.md glossary.md diff --git a/src/doc/trpl/macros.md b/src/doc/trpl/macros.md index e69de29bb2d1d..6d21cb59383c7 100644 --- a/src/doc/trpl/macros.md +++ b/src/doc/trpl/macros.md @@ -0,0 +1,663 @@ +% Macros + +By now you've learned about many of the tools Rust provides for abstracting and +reusing code. These units of code reuse have a rich semantic structure. For +example, functions have a type signature, type parameters have trait bounds, +and overloaded functions must belong to a particular trait. + +This structure means that Rust's core abstractions have powerful compile-time +correctness checking. But this comes at the price of reduced flexibility. If +you visually identify a pattern of repeated code, you may find it's difficult +or cumbersome to express that pattern as a generic function, a trait, or +anything else within Rust's semantics. + +Macros allow us to abstract at a *syntactic* level. A macro invocation is +shorthand for an "expanded" syntactic form. This expansion happens early in +compilation, before any static checking. As a result, macros can capture many +patterns of code reuse that Rust's core abstractions cannot. + +The drawback is that macro-based code can be harder to understand, because +fewer of the built-in rules apply. Like an ordinary function, a well-behaved +macro can be used without understanding its implementation. However, it can be +difficult to design a well-behaved macro! Additionally, compiler errors in +macro code are harder to interpret, because they describe problems in the +expanded code, not the source-level form that developers use. + +These drawbacks make macros something of a "feature of last resort". That's not +to say that macros are bad; they are part of Rust because sometimes they're +needed for truly concise, well-abstracted code. Just keep this tradeoff in +mind. + +# Defining a macro + +You may have seen the `vec!` macro, used to initialize a [vector][] with any +number of elements. + +[vector]: arrays-vectors-and-slices.html + +```rust +let x: Vec = vec![1, 2, 3]; +# assert_eq!(x, [1, 2, 3]); +``` + +This can't be an ordinary function, because it takes any number of arguments. +But we can imagine it as syntactic shorthand for + +```rust +let x: Vec = { + let mut temp_vec = Vec::new(); + temp_vec.push(1); + temp_vec.push(2); + temp_vec.push(3); + temp_vec +}; +# assert_eq!(x, [1, 2, 3]); +``` + +We can implement this shorthand, using a macro: [^actual] + +[^actual]: The actual definition of `vec!` in libcollections differs from the + one presented here, for reasons of efficiency and reusability. Some + of these are mentioned in the [advanced macros chapter][]. + +```rust +macro_rules! vec { + ( $( $x:expr ),* ) => { + { + let mut temp_vec = Vec::new(); + $( + temp_vec.push($x); + )* + temp_vec + } + }; +} +# fn main() { +# assert_eq!(vec![1,2,3], [1, 2, 3]); +# } +``` + +Whoa, that's a lot of new syntax! Let's break it down. + +```ignore +macro_rules! vec { ... } +``` + +This says we're defining a macro named `vec`, much as `fn vec` would define a +function named `vec`. In prose, we informally write a macro's name with an +exclamation point, e.g. `vec!`. The exclamation point is part of the invocation +syntax and serves to distinguish a macro from an ordinary function. + +## Matching + +The macro is defined through a series of *rules*, which are pattern-matching +cases. Above, we had + +```ignore +( $( $x:expr ),* ) => { ... }; +``` + +This is like a `match` expression arm, but the matching happens on Rust syntax +trees, at compile time. The semicolon is optional on the last (here, only) +case. The "pattern" on the left-hand side of `=>` is known as a *matcher*. +These have [their own little grammar] within the language. + +[their own little grammar]: ../reference.html#macros + +The matcher `$x:expr` will match any Rust expression, binding that syntax tree +to the *metavariable* `$x`. The identifier `expr` is a *fragment specifier*; +the full possibilities are enumerated in the [advanced macros chapter][]. +Surrounding the matcher with `$(...),*` will match zero or more expressions, +separated by commas. + +Aside from the special matcher syntax, any Rust tokens that appear in a matcher +must match exactly. For example, + +```rust +macro_rules! foo { + (x => $e:expr) => (println!("mode X: {}", $e)); + (y => $e:expr) => (println!("mode Y: {}", $e)); +} + +fn main() { + foo!(y => 3); +} +``` + +will print + +```text +mode Y: 3 +``` + +With + +```rust,ignore +foo!(z => 3); +``` + +we get the compiler error + +```text +error: no rules expected the token `z` +``` + +## Expansion + +The right-hand side of a macro rule is ordinary Rust syntax, for the most part. +But we can splice in bits of syntax captured by the matcher. From the original +example: + +```ignore +$( + temp_vec.push($x); +)* +``` + +Each matched expression `$x` will produce a single `push` statement in the +macro expansion. The repetition in the expansion proceeds in "lockstep" with +repetition in the matcher (more on this in a moment). + +Because `$x` was already declared as matching an expression, we don't repeat +`:expr` on the right-hand side. Also, we don't include a separating comma as +part of the repetition operator. Instead, we have a terminating semicolon +within the repeated block. + +Another detail: the `vec!` macro has *two* pairs of braces on the right-hand +side. They are often combined like so: + +```ignore +macro_rules! foo { + () => {{ + ... + }} +} +``` + +The outer braces are part of the syntax of `macro_rules!`. In fact, you can use +`()` or `[]` instead. They simply delimit the right-hand side as a whole. + +The inner braces are part of the expanded syntax. Remember, the `vec!` macro is +used in an expression context. To write an expression with multiple statements, +including `let`-bindings, we use a block. If your macro expands to a single +expression, you don't need this extra layer of braces. + +Note that we never *declared* that the macro produces an expression. In fact, +this is not determined until we use the macro as an expression. With care, you +can write a macro whose expansion works in several contexts. For example, +shorthand for a data type could be valid as either an expression or a pattern. + +## Repetition + +The repetition operator follows two principal rules: + +1. `$(...)*` walks through one "layer" of repetitions, for all of the `$name`s + it contains, in lockstep, and +2. each `$name` must be under at least as many `$(...)*`s as it was matched + against. If it is under more, it'll be duplicated, as appropriate. + +This baroque macro illustrates the duplication of variables from outer +repetition levels. + +```rust +macro_rules! o_O { + ( + $( + $x:expr; [ $( $y:expr ),* ] + );* + ) => { + &[ $($( $x + $y ),*),* ] + } +} + +fn main() { + let a: &[i32] + = o_O!(10; [1, 2, 3]; + 20; [4, 5, 6]); + + assert_eq!(a, [11, 12, 13, 24, 25, 26]); +} +``` + +That's most of the matcher syntax. These examples use `$(...)*`, which is a +"zero or more" match. Alternatively you can write `$(...)+` for a "one or +more" match. Both forms optionally include a separator, which can be any token +except `+` or `*`. + +This system is based on +"[Macro-by-Example](http://www.cs.indiana.edu/ftp/techreports/TR206.pdf)" +(PDF link). + +# Hygiene + +Some languages implement macros using simple text substitution, which leads to +various problems. For example, this C program prints `13` instead of the +expected `25`. + +```text +#define FIVE_TIMES(x) 5 * x + +int main() { + printf("%d\n", FIVE_TIMES(2 + 3)); + return 0; +} +``` + +After expansion we have `5 * 2 + 3`, and multiplication has greater precedence +than addition. If you've used C macros a lot, you probably know the standard +idioms for avoiding this problem, as well as five or six others. In Rust, we +don't have to worry about it. + +```rust +macro_rules! five_times { + ($x:expr) => (5 * $x); +} + +fn main() { + assert_eq!(25, five_times!(2 + 3)); +} +``` + +The metavariable `$x` is parsed as a single expression node, and keeps its +place in the syntax tree even after substitution. + +Another common problem in macro systems is *variable capture*. Here's a C +macro, using [a GNU C extension] to emulate Rust's expression blocks. + +[a GNU C extension]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html + +```text +#define LOG(msg) ({ \ + int state = get_log_state(); \ + if (state > 0) { \ + printf("log(%d): %s\n", state, msg); \ + } \ +}) +``` + +Here's a simple use case that goes terribly wrong: + +```text +const char *state = "reticulating splines"; +LOG(state) +``` + +This expands to + +```text +const char *state = "reticulating splines"; +int state = get_log_state(); +if (state > 0) { + printf("log(%d): %s\n", state, state); +} +``` + +The second variable named `state` shadows the first one. This is a problem +because the print statement should refer to both of them. + +The equivalent Rust macro has the desired behavior. + +```rust +# fn get_log_state() -> i32 { 3 } +macro_rules! log { + ($msg:expr) => {{ + let state: i32 = get_log_state(); + if state > 0 { + println!("log({}): {}", state, $msg); + } + }}; +} + +fn main() { + let state: &str = "reticulating splines"; + log!(state); +} +``` + +This works because Rust has a [hygienic macro system][]. Each macro expansion +happens in a distinct *syntax context*, and each variable is tagged with the +syntax context where it was introduced. It's as though the variable `state` +inside `main` is painted a different "color" from the variable `state` inside +the macro, and therefore they don't conflict. + +[hygienic macro system]: http://en.wikipedia.org/wiki/Hygienic_macro + +This also restricts the ability of macros to introduce new bindings at the +invocation site. Code such as the following will not work: + +```rust,ignore +macro_rules! foo { + () => (let x = 3); +} + +fn main() { + foo!(); + println!("{}", x); +} +``` + +Instead you need to pass the variable name into the invocation, so it's tagged +with the right syntax context. + +```rust +macro_rules! foo { + ($v:ident) => (let $v = 3); +} + +fn main() { + foo!(x); + println!("{}", x); +} +``` + +This holds for `let` bindings and loop labels, but not for [items][]. +So the following code does compile: + +```rust +macro_rules! foo { + () => (fn x() { }); +} + +fn main() { + foo!(); + x(); +} +``` + +[items]: ../reference.html#items + +# Recursive macros + +A macro's expansion can include more macro invocations, including invocations +of the very same macro being expanded. These recursive macros are useful for +processing tree-structured input, as illustrated by this (simplistic) HTML +shorthand: + +```rust +# #![allow(unused_must_use)] +macro_rules! write_html { + ($w:expr, ) => (()); + + ($w:expr, $e:tt) => (write!($w, "{}", $e)); + + ($w:expr, $tag:ident [ $($inner:tt)* ] $($rest:tt)*) => {{ + write!($w, "<{}>", stringify!($tag)); + write_html!($w, $($inner)*); + write!($w, "", stringify!($tag)); + write_html!($w, $($rest)*); + }}; +} + +fn main() { +# // FIXME(#21826) + use std::fmt::Write; + let mut out = String::new(); + + write_html!(&mut out, + html[ + head[title["Macros guide"]] + body[h1["Macros are the best!"]] + ]); + + assert_eq!(out, + "Macros guide\ +

Macros are the best!

"); +} +``` + +# Debugging macro code + +To see the results of expanding macros, run `rustc --pretty expanded`. The +output represents a whole crate, so you can also feed it back in to `rustc`, +which will sometimes produce better error messages than the original +compilation. Note that the `--pretty expanded` output may have a different +meaning if multiple variables of the same name (but different syntax contexts) +are in play in the same scope. In this case `--pretty expanded,hygiene` will +tell you about the syntax contexts. + +`rustc` provides two syntax extensions that help with macro debugging. For now, +they are unstable and require feature gates. + +* `log_syntax!(...)` will print its arguments to standard output, at compile + time, and "expand" to nothing. + +* `trace_macros!(true)` will enable a compiler message every time a macro is + expanded. Use `trace_macros!(false)` later in expansion to turn it off. + +# Syntactic requirements + +Even when Rust code contains un-expanded macros, it can be parsed as a full +[syntax tree][ast]. This property can be very useful for editors and other +tools that process code. It also has a few consequences for the design of +Rust's macro system. + +[ast]: glossary.html#abstract-syntax-tree + +One consequence is that Rust must determine, when it parses a macro invocation, +whether the macro stands in for + +* zero or more items, +* zero or more methods, +* an expression, +* a statement, or +* a pattern. + +A macro invocation within a block could stand for some items, or for an +expression / statement. Rust uses a simple rule to resolve this ambiguity. A +macro invocation that stands for items must be either + +* delimited by curly braces, e.g. `foo! { ... }`, or +* terminated by a semicolon, e.g. `foo!(...);` + +Another consequence of pre-expansion parsing is that the macro invocation must +consist of valid Rust tokens. Furthermore, parentheses, brackets, and braces +must be balanced within a macro invocation. For example, `foo!([)` is +forbidden. This allows Rust to know where the macro invocation ends. + +More formally, the macro invocation body must be a sequence of *token trees*. +A token tree is defined recursively as either + +* a sequence of token trees surrounded by matching `()`, `[]`, or `{}`, or +* any other single token. + +Within a matcher, each metavariable has a *fragment specifier*, identifying +which syntactic form it matches. + +* `ident`: an identifier. Examples: `x`; `foo`. +* `path`: a qualified name. Example: `T::SpecialA`. +* `expr`: an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`; `f(42)`. +* `ty`: a type. Examples: `i32`; `Vec<(char, String)>`; `&T`. +* `pat`: a pattern. Examples: `Some(t)`; `(17, 'a')`; `_`. +* `stmt`: a single statement. Example: `let x = 3`. +* `block`: a brace-delimited sequence of statements. Example: + `{ log(error, "hi"); return 12; }`. +* `item`: an [item][]. Examples: `fn foo() { }`; `struct Bar;`. +* `meta`: a "meta item", as found in attributes. Example: `cfg(target_os = "windows")`. +* `tt`: a single token tree. + +There are additional rules regarding the next token after a metavariable: + +* `expr` variables must be followed by one of: `=> , ;` +* `ty` and `path` variables must be followed by one of: `=> , : = > as` +* `pat` variables must be followed by one of: `=> , =` +* Other variables may be followed by any token. + +These rules provide some flexibility for Rust's syntax to evolve without +breaking existing macros. + +The macro system does not deal with parse ambiguity at all. For example, the +grammar `$($t:ty)* $e:expr` will always fail to parse, because the parser would +be forced to choose between parsing `$t` and parsing `$e`. Changing the +invocation syntax to put a distinctive token in front can solve the problem. In +this case, you can write `$(T $t:ty)* E $e:exp`. + +[item]: ../reference.html#items + +# Scoping and macro import/export + +Macros are expanded at an early stage in compilation, before name resolution. +One downside is that scoping works differently for macros, compared to other +constructs in the language. + +Definition and expansion of macros both happen in a single depth-first, +lexical-order traversal of a crate's source. So a macro defined at module scope +is visible to any subsequent code in the same module, which includes the body +of any subsequent child `mod` items. + +A macro defined within the body of a single `fn`, or anywhere else not at +module scope, is visible only within that item. + +If a module has the `macro_use` attribute, its macros are also visible in its +parent module after the child's `mod` item. If the parent also has `macro_use` +then the macros will be visible in the grandparent after the parent's `mod` +item, and so forth. + +The `macro_use` attribute can also appear on `extern crate`. In this context +it controls which macros are loaded from the external crate, e.g. + +```rust,ignore +#[macro_use(foo, bar)] +extern crate baz; +``` + +If the attribute is given simply as `#[macro_use]`, all macros are loaded. If +there is no `#[macro_use]` attribute then no macros are loaded. Only macros +defined with the `#[macro_export]` attribute may be loaded. + +To load a crate's macros *without* linking it into the output, use `#[no_link]` +as well. + +An example: + +```rust +macro_rules! m1 { () => (()) } + +// visible here: m1 + +mod foo { + // visible here: m1 + + #[macro_export] + macro_rules! m2 { () => (()) } + + // visible here: m1, m2 +} + +// visible here: m1 + +macro_rules! m3 { () => (()) } + +// visible here: m1, m3 + +#[macro_use] +mod bar { + // visible here: m1, m3 + + macro_rules! m4 { () => (()) } + + // visible here: m1, m3, m4 +} + +// visible here: m1, m3, m4 +# fn main() { } +``` + +When this library is loaded with `#[macro_use] extern crate`, only `m2` will +be imported. + +The Rust Reference has a [listing of macro-related +attributes](../reference.html#macro--and-plugin-related-attributes). + +# The variable `$crate` + +A further difficulty occurs when a macro is used in multiple crates. Say that +`mylib` defines + +```rust +pub fn increment(x: u32) -> u32 { + x + 1 +} + +#[macro_export] +macro_rules! inc_a { + ($x:expr) => ( ::increment($x) ) +} + +#[macro_export] +macro_rules! inc_b { + ($x:expr) => ( ::mylib::increment($x) ) +} +# fn main() { } +``` + +`inc_a` only works within `mylib`, while `inc_b` only works outside the +library. Furthermore, `inc_b` will break if the user imports `mylib` under +another name. + +Rust does not (yet) have a hygiene system for crate references, but it does +provide a simple workaround for this problem. Within a macro imported from a +crate named `foo`, the special macro variable `$crate` will expand to `::foo`. +By contrast, when a macro is defined and then used in the same crate, `$crate` +will expand to nothing. This means we can write + +```rust +#[macro_export] +macro_rules! inc { + ($x:expr) => ( $crate::increment($x) ) +} +# fn main() { } +``` + +to define a single macro that works both inside and outside our library. The +function name will expand to either `::increment` or `::mylib::increment`. + +To keep this system simple and correct, `#[macro_use] extern crate ...` may +only appear at the root of your crate, not inside `mod`. This ensures that +`$crate` is a single identifier. + +# The deep end + +The introductory chapter mentioned recursive macros, but it did not give the +full story. Recursive macros are useful for another reason: Each recursive +invocation gives you another opportunity to pattern-match the macro's +arguments. + +As an extreme example, it is possible, though hardly advisable, to implement +the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton +within Rust's macro system. + +```rust +macro_rules! bct { + // cmd 0: d ... => ... + (0, $($ps:tt),* ; $_d:tt) + => (bct!($($ps),*, 0 ; )); + (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*) + => (bct!($($ps),*, 0 ; $($ds),*)); + + // cmd 1p: 1 ... => 1 ... p + (1, $p:tt, $($ps:tt),* ; 1) + => (bct!($($ps),*, 1, $p ; 1, $p)); + (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p)); + + // cmd 1p: 0 ... => 0 ... + (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; $($ds),*)); + + // halt on empty data string + ( $($ps:tt),* ; ) + => (()); +} +``` + +Exercise: use macros to reduce duplication in the above definition of the +`bct!` macro. + +# Procedural macros + +If Rust's macro system can't do what you need, you may want to write a +[compiler plugin](plugins.html) instead. Compared to `macro_rules!` +macros, this is significantly more work, the interfaces are much less stable, +and bugs can be much harder to track down. In exchange you get the +flexibility of running arbitrary Rust code within the compiler. Syntax +extension plugins are sometimes called *procedural macros* for this reason. diff --git a/src/doc/trpl/match.md b/src/doc/trpl/match.md index e69de29bb2d1d..73bc775a1b290 100644 --- a/src/doc/trpl/match.md +++ b/src/doc/trpl/match.md @@ -0,0 +1,156 @@ +% Match + +Often, a simple `if`/`else` isn't enough, because you have more than two +possible options. Also, `else` conditions can get incredibly complicated, so +what's the solution? + +Rust has a keyword, `match`, that allows you to replace complicated `if`/`else` +groupings with something more powerful. Check it out: + +```{rust} +let x = 5; + +match x { + 1 => println!("one"), + 2 => println!("two"), + 3 => println!("three"), + 4 => println!("four"), + 5 => println!("five"), + _ => println!("something else"), +} +``` + +`match` takes an expression and then branches based on its value. Each *arm* of +the branch is of the form `val => expression`. When the value matches, that arm's +expression will be evaluated. It's called `match` because of the term 'pattern +matching', which `match` is an implementation of. + +So what's the big advantage here? Well, there are a few. First of all, `match` +enforces *exhaustiveness checking*. Do you see that last arm, the one with the +underscore (`_`)? If we remove that arm, Rust will give us an error: + +```text +error: non-exhaustive patterns: `_` not covered +``` + +In other words, Rust is trying to tell us we forgot a value. Because `x` is an +integer, Rust knows that it can have a number of different values – for example, +`6`. Without the `_`, however, there is no arm that could match, and so Rust refuses +to compile. `_` acts like a *catch-all arm*. If none of the other arms match, +the arm with `_` will, and since we have this catch-all arm, we now have an arm +for every possible value of `x`, and so our program will compile successfully. + +`match` statements also destructure enums, as well. Remember this code from the +section on enums? + +```{rust} +use std::cmp::Ordering; + +fn cmp(a: i32, b: i32) -> Ordering { + if a < b { Ordering::Less } + else if a > b { Ordering::Greater } + else { Ordering::Equal } +} + +fn main() { + let x = 5; + let y = 10; + + let ordering = cmp(x, y); + + if ordering == Ordering::Less { + println!("less"); + } else if ordering == Ordering::Greater { + println!("greater"); + } else if ordering == Ordering::Equal { + println!("equal"); + } +} +``` + +We can re-write this as a `match`: + +```{rust} +use std::cmp::Ordering; + +fn cmp(a: i32, b: i32) -> Ordering { + if a < b { Ordering::Less } + else if a > b { Ordering::Greater } + else { Ordering::Equal } +} + +fn main() { + let x = 5; + let y = 10; + + match cmp(x, y) { + Ordering::Less => println!("less"), + Ordering::Greater => println!("greater"), + Ordering::Equal => println!("equal"), + } +} +``` + +This version has way less noise, and it also checks exhaustively to make sure +that we have covered all possible variants of `Ordering`. With our `if`/`else` +version, if we had forgotten the `Greater` case, for example, our program would +have happily compiled. If we forget in the `match`, it will not. Rust helps us +make sure to cover all of our bases. + +`match` expressions also allow us to get the values contained in an `enum` +(also known as destructuring) as follows: + +```{rust} +enum OptionalInt { + Value(i32), + Missing, +} + +fn main() { + let x = OptionalInt::Value(5); + let y = OptionalInt::Missing; + + match x { + OptionalInt::Value(n) => println!("x is {}", n), + OptionalInt::Missing => println!("x is missing!"), + } + + match y { + OptionalInt::Value(n) => println!("y is {}", n), + OptionalInt::Missing => println!("y is missing!"), + } +} +``` + +That is how you can get and use the values contained in `enum`s. +It can also allow us to handle errors or unexpected computations; for example, a +function that is not guaranteed to be able to compute a result (an `i32` here) +could return an `OptionalInt`, and we would handle that value with a `match`. +As you can see, `enum` and `match` used together are quite useful! + +`match` is also an expression, which means we can use it on the right-hand +side of a `let` binding or directly where an expression is used. We could +also implement the previous example like this: + +```{rust} +use std::cmp::Ordering; + +fn cmp(a: i32, b: i32) -> Ordering { + if a < b { Ordering::Less } + else if a > b { Ordering::Greater } + else { Ordering::Equal } +} + +fn main() { + let x = 5; + let y = 10; + + println!("{}", match cmp(x, y) { + Ordering::Less => "less", + Ordering::Greater => "greater", + Ordering::Equal => "equal", + }); +} +``` + +Sometimes, it's a nice pattern. diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md index e69de29bb2d1d..f6eacd0a84288 100644 --- a/src/doc/trpl/method-syntax.md +++ b/src/doc/trpl/method-syntax.md @@ -0,0 +1,232 @@ +% Method Syntax + +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(x))); +``` + +We would read this left-to right, and so we see "baz bar foo." But this isn't the +order that the functions would get called in, that's inside-out: "foo bar baz." +Wouldn't it be nice if we could do this instead? + +```{rust,ignore} +x.foo().bar().baz(); +``` + +Luckily, as you may have guessed with the leading question, you can! Rust provides +the ability to use this *method call syntax* via the `impl` keyword. + +## Method calls + +Here's how it works: + +```{rust} +# #![feature(core)] +struct Circle { + x: f64, + y: f64, + radius: f64, +} + +impl Circle { + fn area(&self) -> f64 { + std::f64::consts::PI * (self.radius * self.radius) + } +} + +fn main() { + let c = Circle { x: 0.0, y: 0.0, radius: 2.0 }; + println!("{}", c.area()); +} +``` + +This will print `12.566371`. + +We've made a struct that represents a circle. We then write an `impl` block, +and inside it, define a method, `area`. Methods take a special first +parameter, of which there are three variants: `self`, `&self`, and `&mut self`. +You can think of this first parameter as being the `x` in `x.foo()`. The three +variants correspond to the three kinds of thing `x` could be: `self` if it's +just a value on the stack, `&self` if it's a reference, and `&mut self` if it's +a mutable reference. We should default to using `&self`, as you should prefer +borrowing over taking ownership, as well as taking immutable references +over mutable ones. Here's an example of all three variants: + +```rust +struct Circle { + x: f64, + y: f64, + radius: f64, +} + +impl Circle { + fn reference(&self) { + println!("taking self by reference!"); + } + + fn mutable_reference(&mut self) { + println!("taking self by mutable reference!"); + } + + fn takes_ownership(self) { + println!("taking ownership of self!"); + } +} +``` + +Finally, as you may remember, the value of the area of a circle is `π*r²`. +Because we took the `&self` parameter to `area`, we can use it just like any +other parameter. Because we know it's a `Circle`, we can access the `radius` +just like we would with any other struct. An import of π and some +multiplications later, and we have our area. + +## Chaining method calls + +So, now we know how to call a method, such as `foo.bar()`. But what about our +original example, `foo.bar().baz()`? This is called 'method chaining', and we +can do it by returning `self`. + +``` +# #![feature(core)] +struct Circle { + x: f64, + y: f64, + radius: f64, +} + +impl Circle { + fn area(&self) -> f64 { + std::f64::consts::PI * (self.radius * self.radius) + } + + fn grow(&self, increment: f64) -> Circle { + Circle { x: self.x, y: self.y, radius: self.radius + increment } + } +} + +fn main() { + let c = Circle { x: 0.0, y: 0.0, radius: 2.0 }; + println!("{}", c.area()); + + let d = c.grow(2.0).area(); + println!("{}", d); +} +``` + +Check the return type: + +``` +# struct Circle; +# impl Circle { +fn grow(&self) -> Circle { +# Circle } } +``` + +We just say we're returning a `Circle`. With this method, we can grow a new +circle to any arbitrary size. + +## Static methods + +You can also define methods that do not take a `self` parameter. Here's a +pattern that's very common in Rust code: + +``` +struct Circle { + x: f64, + y: f64, + radius: f64, +} + +impl Circle { + fn new(x: f64, y: f64, radius: f64) -> Circle { + Circle { + x: x, + y: y, + radius: radius, + } + } +} + +fn main() { + let c = Circle::new(0.0, 0.0, 2.0); +} +``` + +This *static method* builds a new `Circle` for us. Note that static methods +are called with the `Struct::method()` syntax, rather than the `ref.method()` +syntax. + +## Builder Pattern + +Let's say that we want our users to be able to create Circles, but we will +allow them to only set the properties they care about. Otherwise, the `x` +and `y` attributes will be `0.0`, and the `radius` will be `1.0`. Rust doesn't +have method overloading, named arguments, or variable arguments. We employ +the builder pattern instead. It looks like this: + +``` +# #![feature(core)] +struct Circle { + x: f64, + y: f64, + radius: f64, +} + +impl Circle { + fn area(&self) -> f64 { + std::f64::consts::PI * (self.radius * self.radius) + } +} + +struct CircleBuilder { + x: f64, + y: f64, + radius: f64, +} + +impl CircleBuilder { + fn new() -> CircleBuilder { + CircleBuilder { x: 0.0, y: 0.0, radius: 0.0, } + } + + fn x(&mut self, coordinate: f64) -> &mut CircleBuilder { + self.x = coordinate; + self + } + + fn y(&mut self, coordinate: f64) -> &mut CircleBuilder { + self.y = coordinate; + self + } + + fn radius(&mut self, radius: f64) -> &mut CircleBuilder { + self.radius = radius; + self + } + + fn finalize(&self) -> Circle { + Circle { x: self.x, y: self.y, radius: self.radius } + } +} + +fn main() { + let c = CircleBuilder::new() + .x(1.0) + .y(2.0) + .radius(2.0) + .finalize(); + + println!("area: {}", c.area()); + println!("x: {}", c.x); + println!("y: {}", c.y); +} +``` + +What we've done here is make another struct, `CircleBuilder`. We've defined our +builder methods on it. We've also defined our `area()` method on `Circle`. We +also made one more method on `CircleBuilder`: `finalize()`. This method creates +our final `Circle` from the builder. Now, we've used the type system to enforce +our concerns: we can use the methods on `CircleBuilder` to constrain making +`Circle`s in any way we choose. diff --git a/src/doc/trpl/move-semantics.md b/src/doc/trpl/move-semantics.md index e69de29bb2d1d..6917d7f8b8e0f 100644 --- a/src/doc/trpl/move-semantics.md +++ b/src/doc/trpl/move-semantics.md @@ -0,0 +1,3 @@ +% Move Semantics + +Coming Soon diff --git a/src/doc/trpl/mutability.md b/src/doc/trpl/mutability.md index e69de29bb2d1d..ccb03c7f85f69 100644 --- a/src/doc/trpl/mutability.md +++ b/src/doc/trpl/mutability.md @@ -0,0 +1,3 @@ +% Mutability + +Coming Soon diff --git a/src/doc/trpl/nightly-rust.md b/src/doc/trpl/nightly-rust.md index d69831c237838..1b58b73994dc9 100644 --- a/src/doc/trpl/nightly-rust.md +++ b/src/doc/trpl/nightly-rust.md @@ -1,4 +1,4 @@ -% Unstable Rust +% Nightly Rust Rust provides three distribution channels for Rust: nightly, beta, and stable. Unstable features are only available on nightly Rust. For more details on this diff --git a/src/doc/trpl/no-stdlib.md b/src/doc/trpl/no-stdlib.md index e69de29bb2d1d..094c82a08cc9d 100644 --- a/src/doc/trpl/no-stdlib.md +++ b/src/doc/trpl/no-stdlib.md @@ -0,0 +1,168 @@ +% No stdlib + +By default, `std` is linked to every Rust crate. In some contexts, +this is undesirable, and can be avoided with the `#![no_std]` +attribute attached to the crate. + +```ignore +// a minimal library +#![crate_type="lib"] +#![feature(no_std)] +#![no_std] +# // fn main() {} tricked you, rustdoc! +``` + +Obviously there's more to life than just libraries: one can use +`#[no_std]` with an executable, controlling the entry point is +possible in two ways: the `#[start]` attribute, or overriding the +default shim for the C `main` function with your own. + +The function marked `#[start]` is passed the command line parameters +in the same format as C: + +``` +#![feature(lang_items, start, no_std, libc)] +#![no_std] + +// Pull in the system libc library for what crt0.o likely requires +extern crate libc; + +// Entry point for this program +#[start] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} + +// These functions and traits are used by the compiler, but not +// for a bare-bones hello world. These are normally +// provided by libstd. +#[lang = "stack_exhausted"] extern fn stack_exhausted() {} +#[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +# // fn main() {} tricked you, rustdoc! +``` + +To override the compiler-inserted `main` shim, one has to disable it +with `#![no_main]` and then create the appropriate symbol with the +correct ABI and the correct name, which requires overriding the +compiler's name mangling too: + +```ignore +#![feature(no_std)] +#![no_std] +#![no_main] +#![feature(lang_items, start)] + +extern crate libc; + +#[no_mangle] // ensure that this symbol is called `main` in the output +pub extern fn main(argc: i32, argv: *const *const u8) -> i32 { + 0 +} + +#[lang = "stack_exhausted"] extern fn stack_exhausted() {} +#[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +# // fn main() {} tricked you, rustdoc! +``` + + +The compiler currently makes a few assumptions about symbols which are available +in the executable to call. Normally these functions are provided by the standard +library, but without it you must define your own. + +The first of these three functions, `stack_exhausted`, is invoked whenever stack +overflow is detected. This function has a number of restrictions about how it +can be called and what it must do, but if the stack limit register is not being +maintained then a thread always has an "infinite stack" and this function +shouldn't get triggered. + +The second of these three functions, `eh_personality`, is used by the +failure mechanisms of the compiler. This is often mapped to GCC's +personality function (see the +[libstd implementation](../std/rt/unwind/index.html) for more +information), but crates which do not trigger a panic can be assured +that this function is never called. The final function, `panic_fmt`, is +also used by the failure mechanisms of the compiler. + +## Using libcore + +> **Note**: the core library's structure is unstable, and it is recommended to +> use the standard library instead wherever possible. + +With the above techniques, we've got a bare-metal executable running some Rust +code. There is a good deal of functionality provided by the standard library, +however, that is necessary to be productive in Rust. If the standard library is +not sufficient, then [libcore](../core/index.html) is designed to be used +instead. + +The core library has very few dependencies and is much more portable than the +standard library itself. Additionally, the core library has most of the +necessary functionality for writing idiomatic and effective Rust code. + +As an example, here is a program that will calculate the dot product of two +vectors provided from C, using idiomatic Rust practices. + +``` +#![feature(lang_items, start, no_std, core, libc)] +#![no_std] + +# extern crate libc; +extern crate core; + +use core::prelude::*; + +use core::mem; + +#[no_mangle] +pub extern fn dot_product(a: *const u32, a_len: u32, + b: *const u32, b_len: u32) -> u32 { + use core::raw::Slice; + + // Convert the provided arrays into Rust slices. + // The core::raw module guarantees that the Slice + // structure has the same memory layout as a &[T] + // slice. + // + // This is an unsafe operation because the compiler + // cannot tell the pointers are valid. + let (a_slice, b_slice): (&[u32], &[u32]) = unsafe { + mem::transmute(( + Slice { data: a, len: a_len as usize }, + Slice { data: b, len: b_len as usize }, + )) + }; + + // Iterate over the slices, collecting the result + let mut ret = 0; + for (i, j) in a_slice.iter().zip(b_slice.iter()) { + ret += (*i) * (*j); + } + return ret; +} + +#[lang = "panic_fmt"] +extern fn panic_fmt(args: &core::fmt::Arguments, + file: &str, + line: u32) -> ! { + loop {} +} + +#[lang = "stack_exhausted"] extern fn stack_exhausted() {} +#[lang = "eh_personality"] extern fn eh_personality() {} +# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 } +# fn main() {} +``` + +Note that there is one extra lang item here which differs from the examples +above, `panic_fmt`. This must be defined by consumers of libcore because the +core library declares panics, but it does not define it. The `panic_fmt` +lang item is this crate's definition of panic, and it must be guaranteed to +never return. + +As can be seen in this example, the core library is intended to provide the +power of Rust in all circumstances, regardless of platform requirements. Further +libraries, such as liballoc, add functionality to libcore which make other +platform-specific assumptions, but continue to be more portable than the +standard library itself. + diff --git a/src/doc/trpl/operators-and-overloading.md b/src/doc/trpl/operators-and-overloading.md index e69de29bb2d1d..f6f9d5cae1921 100644 --- a/src/doc/trpl/operators-and-overloading.md +++ b/src/doc/trpl/operators-and-overloading.md @@ -0,0 +1,3 @@ +% Operators and Overloading + +Coming soon! diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index e69de29bb2d1d..223085cc40b8e 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -0,0 +1,555 @@ +% Ownership + +This guide presents Rust's ownership system. This is one of Rust's most unique +and compelling features, with which Rust developers should become quite +acquainted. Ownership is how Rust achieves its largest goal, memory safety. +The ownership system has a few distinct concepts: *ownership*, *borrowing*, +and *lifetimes*. We'll talk about each one in turn. + +# Meta + +Before we get to the details, two important notes about the ownership system. + +Rust has a focus on safety and speed. It accomplishes these goals through many +*zero-cost abstractions*, which means that in Rust, abstractions cost as little +as possible in order to make them work. The ownership system is a prime example +of a zero cost abstraction. All of the analysis we'll talk about in this guide +is _done at compile time_. You do not pay any run-time cost for any of these +features. + +However, this system does have a certain cost: learning curve. Many new users +to Rust experience something we like to call "fighting with the borrow +checker," where the Rust compiler refuses to compile a program that the author +thinks is valid. This often happens because the programmer's mental model of +how ownership should work doesn't match the actual rules that Rust implements. +You probably will experience similar things at first. There is good news, +however: more experienced Rust developers report that once they work with the +rules of the ownership system for a period of time, they fight the borrow +checker less and less. + +With that in mind, let's learn about ownership. + +# Ownership + +At its core, ownership is about *resources*. For the purposes of the vast +majority of this guide, we will talk about a specific resource: memory. The +concept generalizes to any kind of resource, like a file handle, but to make it +more concrete, we'll focus on memory. + +When your program allocates some memory, it needs some way to deallocate that +memory. Imagine a function `foo` that allocates four bytes of memory, and then +never deallocates that memory. We call this problem *leaking* memory, because +each time we call `foo`, we're allocating another four bytes. Eventually, with +enough calls to `foo`, we will run our system out of memory. That's no good. So +we need some way for `foo` to deallocate those four bytes. It's also important +that we don't deallocate too many times, either. Without getting into the +details, attempting to deallocate memory multiple times can lead to problems. +In other words, any time some memory is allocated, we need to make sure that we +deallocate that memory once and only once. Too many times is bad, not enough +times is bad. The counts must match. + +There's one other important detail with regards to allocating memory. Whenever +we request some amount of memory, what we are given is a handle to that memory. +This handle (often called a *pointer*, when we're referring to memory) is how +we interact with the allocated memory. As long as we have that handle, we can +do something with the memory. Once we're done with the handle, we're also done +with the memory, as we can't do anything useful without a handle to it. + +Historically, systems programming languages require you to track these +allocations, deallocations, and handles yourself. For example, if we want some +memory from the heap in a language like C, we do this: + +```c +{ + int *x = malloc(sizeof(int)); + + // we can now do stuff with our handle x + *x = 5; + + free(x); +} +``` + +The call to `malloc` allocates some memory. The call to `free` deallocates the +memory. There's also bookkeeping about allocating the correct amount of memory. + +Rust combines these two aspects of allocating memory (and other resources) into +a concept called *ownership*. Whenever we request some memory, that handle we +receive is called the *owning handle*. Whenever that handle goes out of scope, +Rust knows that you cannot do anything with the memory anymore, and so +therefore deallocates the memory for you. Here's the equivalent example in +Rust: + +```rust +{ + let x = Box::new(5); +} +``` + +The `Box::new` function creates a `Box` (specifically `Box` in this +case) by allocating a small segment of memory on the heap with enough space to +fit an `i32`. But where in the code is the box deallocated? We said before that +we must have a deallocation for each allocation. Rust handles this for you. It +knows that our handle, `x`, is the owning reference to our box. Rust knows that +`x` will go out of scope at the end of the block, and so it inserts a call to +deallocate the memory at the end of the scope. Because the compiler does this +for us, it's impossible to forget. We always have exactly one deallocation + paired with each of our allocations. + +This is pretty straightforward, but what happens when we want to pass our box +to a function? Let's look at some code: + +```rust +fn main() { + let x = Box::new(5); + + add_one(x); +} + +fn add_one(mut num: Box) { + *num += 1; +} +``` + +This code works, but it's not ideal. For example, let's add one more line of +code, where we print out the value of `x`: + +```{rust,ignore} +fn main() { + let x = Box::new(5); + + add_one(x); + + println!("{}", x); +} + +fn add_one(mut num: Box) { + *num += 1; +} +``` + +This does not compile, and gives us an error: + +```text +error: use of moved value: `x` + println!("{}", x); + ^ +``` + +Remember, we need one deallocation for every allocation. When we try to pass +our box to `add_one`, we would have two handles to the memory: `x` in `main`, +and `num` in `add_one`. If we deallocated the memory when each handle went out +of scope, we would have two deallocations and one allocation, and that's wrong. +So when we call `add_one`, Rust defines `num` as the owner of the handle. And +so, now that we've given ownership to `num`, `x` is invalid. `x`'s value has +"moved" from `x` to `num`. Hence the error: use of moved value `x`. + +To fix this, we can have `add_one` give ownership back when it's done with the +box: + +```rust +fn main() { + let x = Box::new(5); + + let y = add_one(x); + + println!("{}", y); +} + +fn add_one(mut num: Box) -> Box { + *num += 1; + + num +} +``` + +This code will compile and run just fine. Now, we return a `box`, and so the +ownership is transferred back to `y` in `main`. We only have ownership for the +duration of our function before giving it back. This pattern is very common, +and so Rust introduces a concept to describe a handle which temporarily refers +to something another handle owns. It's called *borrowing*, and it's done with +*references*, designated by the `&` symbol. + +# Borrowing + +Here's the current state of our `add_one` function: + +```rust +fn add_one(mut num: Box) -> Box { + *num += 1; + + num +} +``` + +This function takes ownership, because it takes a `Box`, which owns its +contents. But then we give ownership right back. + +In the physical world, you can give one of your possessions to someone for a +short period of time. You still own your possession, you're just letting someone +else use it for a while. We call that *lending* something to someone, and that +person is said to be *borrowing* that something from you. + +Rust's ownership system also allows an owner to lend out a handle for a limited +period. This is also called *borrowing*. Here's a version of `add_one` which +borrows its argument rather than taking ownership: + +```rust +fn add_one(num: &mut i32) { + *num += 1; +} +``` + +This function borrows an `i32` from its caller, and then increments it. When +the function is over, and `num` goes out of scope, the borrow is over. + +We have to change our `main` a bit too: + +```rust +fn main() { + let mut x = 5; + + add_one(&mut x); + + println!("{}", x); +} + +fn add_one(num: &mut i32) { + *num += 1; +} +``` + +We don't need to assign the result of `add_one()` anymore, because it doesn't +return anything anymore. This is because we're not passing ownership back, +since we just borrow, not take ownership. + +# Lifetimes + +Lending out a reference to a resource that someone else owns can be +complicated, however. For example, imagine this set of operations: + +1. I acquire a handle to some kind of resource. +2. I lend you a reference to the resource. +3. I decide I'm done with the resource, and deallocate it, while you still have + your reference. +4. You decide to use the resource. + +Uh oh! Your reference is pointing to an invalid resource. This is called a +*dangling pointer* or "use after free," when the resource is memory. + +To fix this, we have to make sure that step four never happens after step +three. The ownership system in Rust does this through a concept called +*lifetimes*, which describe the scope that a reference is valid for. + +Remember the function that borrowed an `i32`? Let's look at it again. + +```rust +fn add_one(num: &mut i32) { + *num += 1; +} +``` + +Rust has a feature called *lifetime elision*, which allows you to not write +lifetime annotations in certain circumstances. This is one of them. We will +cover the others later. Without eliding the lifetimes, `add_one` looks like +this: + +```rust +fn add_one<'a>(num: &'a mut i32) { + *num += 1; +} +``` + +The `'a` is called a *lifetime*. Most lifetimes are used in places where +short names like `'a`, `'b` and `'c` are clearest, but it's often useful to +have more descriptive names. Let's dig into the syntax in a bit more detail: + +```{rust,ignore} +fn add_one<'a>(...) +``` + +This part _declares_ our lifetimes. This says that `add_one` has one lifetime, +`'a`. If we had two, it would look like this: + +```{rust,ignore} +fn add_two<'a, 'b>(...) +``` + +Then in our parameter list, we use the lifetimes we've named: + +```{rust,ignore} +...(num: &'a mut i32) +``` + +If you compare `&mut i32` to `&'a mut i32`, they're the same, it's just that the +lifetime `'a` has snuck in between the `&` and the `mut i32`. We read `&mut i32` as "a +mutable reference to an i32" and `&'a mut i32` as "a mutable reference to an i32 with the lifetime 'a.'" + +Why do lifetimes matter? Well, for example, here's some code: + +```rust +struct Foo<'a> { + x: &'a i32, +} + +fn main() { + let y = &5; // this is the same as `let _y = 5; let y = &_y;` + let f = Foo { x: y }; + + println!("{}", f.x); +} +``` + +As you can see, `struct`s can also have lifetimes. In a similar way to functions, + +```{rust} +struct Foo<'a> { +# x: &'a i32, +# } +``` + +declares a lifetime, and + +```rust +# struct Foo<'a> { +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. + +## Thinking in scopes + +A way to think about lifetimes is to visualize the scope that a reference is +valid for. For example: + +```rust +fn main() { + let y = &5; // -+ y goes into scope + // | + // stuff // | + // | +} // -+ y goes out of scope +``` + +Adding in our `Foo`: + +```rust +struct Foo<'a> { + x: &'a i32, +} + +fn main() { + let y = &5; // -+ y goes into scope + let f = Foo { x: y }; // -+ f goes into scope + // stuff // | + // | +} // -+ f and y go out of scope +``` + +Our `f` lives within the scope of `y`, so everything works. What if it didn't? +This code won't work: + +```{rust,ignore} +struct Foo<'a> { + x: &'a i32, +} + +fn main() { + let x; // -+ x goes into scope + // | + { // | + let y = &5; // ---+ y goes into scope + let f = Foo { x: y }; // ---+ f goes into scope + x = &f.x; // | | error here + } // ---+ f and y go out of scope + // | + println!("{}", x); // | +} // -+ x goes out of scope +``` + +Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope +of `x`. But when we do `x = &f.x`, we make `x` a reference to something that's +about to go out of scope. + +Named lifetimes are a way of giving these scopes a name. Giving something a +name is the first step towards being able to talk about it. + +## 'static + +The lifetime named *static* is a special lifetime. It signals that something +has the lifetime of the entire program. Most Rust programmers first come across +`'static` when dealing with strings: + +```rust +let x: &'static str = "Hello, world."; +``` + +String literals have the type `&'static str` because the reference is always +alive: they are baked into the data segment of the final binary. Another +example are globals: + +```rust +static FOO: i32 = 5; +let x: &'static i32 = &FOO; +``` + +This adds an `i32` to the data segment of the binary, and `x` is a reference +to it. + +# Shared Ownership + +In all the examples we've considered so far, we've assumed that each handle has +a singular owner. But sometimes, this doesn't work. Consider a car. Cars have +four wheels. We would want a wheel to know which car it was attached to. But +this won't work: + +```{rust,ignore} +struct Car { + name: String, +} + +struct Wheel { + size: i32, + owner: Car, +} + +fn main() { + let car = Car { name: "DeLorean".to_string() }; + + for _ in 0..4 { + Wheel { size: 360, owner: car }; + } +} +``` + +We try to make four `Wheel`s, each with a `Car` that it's attached to. But the +compiler knows that on the second iteration of the loop, there's a problem: + +```text +error: use of moved value: `car` + Wheel { size: 360, owner: car }; + ^~~ +note: `car` moved here because it has type `Car`, which is non-copyable + Wheel { size: 360, owner: car }; + ^~~ +``` + +We need our `Car` to be pointed to by multiple `Wheel`s. We can't do that with +`Box`, because it has a single owner. We can do it with `Rc` instead: + +```rust +use std::rc::Rc; + +struct Car { + name: String, +} + +struct Wheel { + size: i32, + owner: Rc, +} + +fn main() { + let car = Car { name: "DeLorean".to_string() }; + + let car_owner = Rc::new(car); + + for _ in 0..4 { + Wheel { size: 360, owner: car_owner.clone() }; + } +} +``` + +We wrap our `Car` in an `Rc`, getting an `Rc`, and then use the +`clone()` method to make new references. We've also changed our `Wheel` to have +an `Rc` rather than just a `Car`. + +This is the simplest kind of multiple ownership possible. For example, there's +also `Arc`, which uses more expensive atomic instructions to be the +thread-safe counterpart of `Rc`. + +## Lifetime Elision + +Rust supports powerful local type inference in function bodies, but it’s +forbidden in item signatures to allow reasoning about the types just based in +the item signature alone. However, for ergonomic reasons a very restricted +secondary inference algorithm called “lifetime elision” applies in function +signatures. It infers only based on the signature components themselves and not +based on the body of the function, only infers lifetime parameters, and does +this with only three easily memorizable and unambiguous rules. This makes +lifetime elision a shorthand for writing an item signature, while not hiding +away the actual types involved as full local inference would if applied to it. + +When talking about lifetime elision, we use the term *input lifetime* and +*output lifetime*. An *input lifetime* is a lifetime associated with a parameter +of a function, and an *output lifetime* is a lifetime associated with the return +value of a function. For example, this function has an input lifetime: + +```{rust,ignore} +fn foo<'a>(bar: &'a str) +``` + +This one has an output lifetime: + +```{rust,ignore} +fn foo<'a>() -> &'a str +``` + +This one has a lifetime in both positions: + +```{rust,ignore} +fn foo<'a>(bar: &'a str) -> &'a str +``` + +Here are the three rules: + +* Each elided lifetime in a function's arguments becomes a distinct lifetime + parameter. + +* If there is exactly one input lifetime, elided or not, that lifetime is + assigned to all elided lifetimes in the return values of that function. + +* If there are multiple input lifetimes, but one of them is `&self` or `&mut + self`, the lifetime of `self` is assigned to all elided output lifetimes. + +Otherwise, it is an error to elide an output lifetime. + +### Examples + +Here are some examples of functions with elided lifetimes. We've paired each +example of an elided lifetime with its expanded form. + +```{rust,ignore} +fn print(s: &str); // elided +fn print<'a>(s: &'a str); // expanded + +fn debug(lvl: u32, s: &str); // elided +fn debug<'a>(lvl: u32, s: &'a str); // expanded + +// In the preceding example, `lvl` doesn't need a lifetime because it's not a +// reference (`&`). Only things relating to references (such as a `struct` +// which contains a reference) need lifetimes. + +fn substr(s: &str, until: u32) -> &str; // elided +fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded + +fn get_str() -> &str; // ILLEGAL, no inputs + +fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs +fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is unclear + +fn get_mut(&mut self) -> &mut T; // elided +fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded + +fn args(&mut self, args: &[T]) -> &mut Command // elided +fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded + +fn new(buf: &mut [u8]) -> BufWriter; // elided +fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded +``` + +# Related Resources + +Coming Soon. diff --git a/src/doc/trpl/patterns.md b/src/doc/trpl/patterns.md index e69de29bb2d1d..4ebf696aa57a0 100644 --- a/src/doc/trpl/patterns.md +++ b/src/doc/trpl/patterns.md @@ -0,0 +1,200 @@ +% Patterns + +We've made use of patterns a few times in the guide: first with `let` bindings, +then with `match` statements. Let's go on a whirlwind tour of all of the things +patterns can do! + +A quick refresher: you can match against literals directly, and `_` acts as an +*any* case: + +```{rust} +let x = 1; + +match x { + 1 => println!("one"), + 2 => println!("two"), + 3 => println!("three"), + _ => println!("anything"), +} +``` + +You can match multiple patterns with `|`: + +```{rust} +let x = 1; + +match x { + 1 | 2 => println!("one or two"), + 3 => println!("three"), + _ => println!("anything"), +} +``` + +You can match a range of values with `...`: + +```{rust} +let x = 1; + +match x { + 1 ... 5 => println!("one through five"), + _ => println!("anything"), +} +``` + +Ranges are mostly used with integers and single characters. + +If you're matching multiple things, via a `|` or a `...`, you can bind +the value to a name with `@`: + +```{rust} +let x = 1; + +match x { + e @ 1 ... 5 => println!("got a range element {}", e), + _ => println!("anything"), +} +``` + +If you're matching on an enum which has variants, you can use `..` to +ignore the value and type in the variant: + +```{rust} +enum OptionalInt { + Value(i32), + Missing, +} + +let x = OptionalInt::Value(5); + +match x { + OptionalInt::Value(..) => println!("Got an int!"), + OptionalInt::Missing => println!("No such luck."), +} +``` + +You can introduce *match guards* with `if`: + +```{rust} +enum OptionalInt { + Value(i32), + Missing, +} + +let x = OptionalInt::Value(5); + +match x { + OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"), + OptionalInt::Value(..) => println!("Got an int!"), + OptionalInt::Missing => println!("No such luck."), +} +``` + +If you're matching on a pointer, you can use the same syntax as you declared it +with. First, `&`: + +```{rust} +let x = &5; + +match x { + &val => println!("Got a value: {}", val), +} +``` + +Here, the `val` inside the `match` has type `i32`. In other words, the left-hand +side of the pattern destructures the value. If we have `&5`, then in `&val`, `val` +would be `5`. + +If you want to get a reference, use the `ref` keyword: + +```{rust} +let x = 5; + +match x { + ref r => println!("Got a reference to {}", r), +} +``` + +Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref` +keyword _creates_ a reference, for use in the pattern. If you need a mutable +reference, `ref mut` will work in the same way: + +```{rust} +let mut x = 5; + +match x { + ref mut mr => println!("Got a mutable reference to {}", mr), +} +``` + +If you have a struct, you can destructure it inside of a pattern: + +```{rust} +# #![allow(non_shorthand_field_patterns)] +struct Point { + x: i32, + y: i32, +} + +let origin = Point { x: 0, y: 0 }; + +match origin { + Point { x: x, y: y } => println!("({},{})", x, y), +} +``` + +If we only care about some of the values, we don't have to give them all names: + +```{rust} +# #![allow(non_shorthand_field_patterns)] +struct Point { + x: i32, + y: i32, +} + +let origin = Point { x: 0, y: 0 }; + +match origin { + Point { x: x, .. } => println!("x is {}", x), +} +``` + +You can do this kind of match on any member, not just the first: + +```{rust} +# #![allow(non_shorthand_field_patterns)] +struct Point { + x: i32, + y: i32, +} + +let origin = Point { x: 0, y: 0 }; + +match origin { + Point { y: y, .. } => println!("y is {}", y), +} +``` + +If you want to match against a slice or array, you can use `&`: + +```{rust} +# #![feature(slice_patterns)] +fn main() { + let v = vec!["match_this", "1"]; + + match &v[..] { + ["match_this", second] => println!("The second element is {}", second), + _ => {}, + } +} +``` + +Whew! That's a lot of different ways to match things, and they can all be +mixed and matched, depending on what you're doing: + +```{rust,ignore} +match x { + Foo { x: Some(ref name), y: None } => ... +} +``` + +Patterns are very powerful. Make good use of them. diff --git a/src/doc/trpl/plugins.md b/src/doc/trpl/plugins.md deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/doc/trpl/primitive-types.md b/src/doc/trpl/primitive-types.md index e69de29bb2d1d..2878e7ce4754e 100644 --- a/src/doc/trpl/primitive-types.md +++ b/src/doc/trpl/primitive-types.md @@ -0,0 +1,3 @@ +% Primitive Types + +Coming Soon! diff --git a/src/doc/trpl/references-and-borrowing.md b/src/doc/trpl/references-and-borrowing.md index e69de29bb2d1d..6acb326958d31 100644 --- a/src/doc/trpl/references-and-borrowing.md +++ b/src/doc/trpl/references-and-borrowing.md @@ -0,0 +1,3 @@ +% References and Borrowing + +Coming Soon! diff --git a/src/doc/trpl/slices.md b/src/doc/trpl/slices.md index e69de29bb2d1d..a31c0ac3c4e69 100644 --- a/src/doc/trpl/slices.md +++ b/src/doc/trpl/slices.md @@ -0,0 +1,21 @@ +% Slices + +A *slice* is a reference to (or "view" into) an array. They are useful for +allowing safe, efficient access to a portion of an array without copying. For +example, you might want to reference just one line of a file read into memory. +By nature, a slice is not created directly, but from an existing variable. +Slices have a length, can be mutable or not, and in many ways behave like +arrays: + +```{rust} +let a = [0, 1, 2, 3, 4]; +let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3 + +for e in middle.iter() { + println!("{}", e); // Prints 1, 2, 3 +} +``` + +You can also take a slice of a vector, `String`, or `&str`, because they are +backed by arrays. Slices have type `&[T]`, which we'll talk about when we cover +generics. diff --git a/src/doc/trpl/static.md b/src/doc/trpl/static.md index e69de29bb2d1d..b29c4952c94e3 100644 --- a/src/doc/trpl/static.md +++ b/src/doc/trpl/static.md @@ -0,0 +1,3 @@ +% `static` + +Coming soon! diff --git a/src/doc/trpl/strings.md b/src/doc/trpl/strings.md index e69de29bb2d1d..2c2e6a8c7c5ac 100644 --- a/src/doc/trpl/strings.md +++ b/src/doc/trpl/strings.md @@ -0,0 +1,61 @@ +% Strings + +Strings are an important concept for any programmer to master. Rust's string +handling system is a bit different from other languages, due to its systems +focus. Any time you have a data structure of variable size, things can get +tricky, and strings are a re-sizable data structure. That being said, Rust's +strings also work differently than in some other systems languages, such as C. + +Let's dig into the details. A *string* is a sequence of Unicode scalar values +encoded as a stream of UTF-8 bytes. All strings are guaranteed to be +validly encoded UTF-8 sequences. Additionally, strings are not null-terminated +and can contain null bytes. + +Rust has two main types of strings: `&str` and `String`. + +The first kind is a `&str`. These are called *string slices*. String literals +are of the type `&str`: + +```{rust} +let string = "Hello there."; // string: &str +``` + +This string is statically allocated, meaning that it's saved inside our +compiled program, and exists for the entire duration it runs. The `string` +binding is a reference to this statically allocated string. String slices +have a fixed size, and cannot be mutated. + +A `String`, on the other hand, is a heap-allocated string. This string +is growable, and is also guaranteed to be UTF-8. `String`s are +commonly created by converting from a string slice using the +`to_string` method. + +```{rust} +let mut s = "Hello".to_string(); // mut s: String +println!("{}", s); + +s.push_str(", world."); +println!("{}", s); +``` + +`String`s will coerce into `&str` with an `&`: + +``` +fn takes_slice(slice: &str) { + println!("Got: {}", slice); +} + +fn main() { + let s = "Hello".to_string(); + takes_slice(&s); +} +``` + +Viewing a `String` as a `&str` is cheap, but converting the `&str` to a +`String` involves allocating memory. No reason to do that unless you have to! + +That's the basics of strings in Rust! They're probably a bit more complicated +than you are used to, if you come from a scripting language, but when the +low-level details matter, they really matter. Just remember that `String`s +allocate memory and control their data, while `&str`s are a reference to +another string, and you'll be all set. diff --git a/src/doc/trpl/structs.md b/src/doc/trpl/structs.md index e69de29bb2d1d..eff1a47761d60 100644 --- a/src/doc/trpl/structs.md +++ b/src/doc/trpl/structs.md @@ -0,0 +1,49 @@ +% Structs + +A struct is another form of a *record type*, just like a tuple. There's a +difference: structs give each element that they contain a name, called a +*field* or a *member*. Check it out: + +```rust +struct Point { + x: i32, + y: i32, +} + +fn main() { + let origin = Point { x: 0, y: 0 }; // origin: Point + + println!("The origin is at ({}, {})", origin.x, origin.y); +} +``` + +There's a lot going on here, so let's break it down. We declare a struct with +the `struct` keyword, and then with a name. By convention, structs begin with a +capital letter and are also camel cased: `PointInSpace`, not `Point_In_Space`. + +We can create an instance of our struct via `let`, as usual, but we use a `key: +value` style syntax to set each field. The order doesn't need to be the same as +in the original declaration. + +Finally, because fields have names, we can access the field through dot +notation: `origin.x`. + +The values in structs are immutable by default, like other bindings in Rust. +Use `mut` to make them mutable: + +```{rust} +struct Point { + x: i32, + y: i32, +} + +fn main() { + let mut point = Point { x: 0, y: 0 }; + + point.x = 5; + + println!("The point is at ({}, {})", point.x, point.y); +} +``` + +This will print `The point is at (5, 0)`. diff --git a/src/doc/trpl/syntax-and-semantics.md b/src/doc/trpl/syntax-and-semantics.md index e69de29bb2d1d..6f992cf688736 100644 --- a/src/doc/trpl/syntax-and-semantics.md +++ b/src/doc/trpl/syntax-and-semantics.md @@ -0,0 +1 @@ +% Syntax and Semantics diff --git a/src/doc/trpl/testing.md b/src/doc/trpl/testing.md index e69de29bb2d1d..8cf126cad95fb 100644 --- a/src/doc/trpl/testing.md +++ b/src/doc/trpl/testing.md @@ -0,0 +1,432 @@ +% Testing + +> Program testing can be a very effective way to show the presence of bugs, but +> it is hopelessly inadequate for showing their absence. +> +> Edsger W. Dijkstra, "The Humble Programmer" (1972) + +Let's talk about how to test Rust code. What we will not be talking about is +the right way to test Rust code. There are many schools of thought regarding +the right and wrong way to write tests. All of these approaches use the same +basic tools, and so we'll show you the syntax for using them. + +# The `test` attribute + +At its simplest, a test in Rust is a function that's annotated with the `test` +attribute. Let's make a new project with Cargo called `adder`: + +```bash +$ cargo new adder +$ cd adder +``` + +Cargo will automatically generate a simple test when you make a new project. +Here's the contents of `src/lib.rs`: + +```rust +#[test] +fn it_works() { +} +``` + +Note the `#[test]`. This attribute indicates that this is a test function. It +currently has no body. That's good enough to pass! We can run the tests with +`cargo test`: + +```bash +$ cargo test + Compiling adder v0.0.1 (file:///home/you/projects/adder) + Running target/adder-91b3e234d4ed382a + +running 1 test +test it_works ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests adder + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` + +Cargo compiled and ran our tests. There are two sets of output here: one +for the test we wrote, and another for documentation tests. We'll talk about +those later. For now, see this line: + +```text +test it_works ... ok +``` + +Note the `it_works`. This comes from the name of our function: + +```rust +fn it_works() { +# } +``` + +We also get a summary line: + +```text +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured +``` + +So why does our do-nothing test pass? Any test which doesn't `panic!` passes, +and any test that does `panic!` fails. Let's make our test fail: + +```rust +#[test] +fn it_works() { + assert!(false); +} +``` + +`assert!` is a macro provided by Rust which takes one argument: if the argument +is `true`, nothing happens. If the argument is false, it `panic!`s. Let's run +our tests again: + +```bash +$ cargo test + Compiling adder v0.0.1 (file:///home/you/projects/adder) + Running target/adder-91b3e234d4ed382a + +running 1 test +test it_works ... FAILED + +failures: + +---- it_works stdout ---- + thread 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3 + + + +failures: + it_works + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured + +thread '
' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247 +``` + +Rust indicates that our test failed: + +```text +test it_works ... FAILED +``` + +And that's reflected in the summary line: + +```text +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured +``` + +We also get a non-zero status code: + +```bash +$ echo $? +101 +``` + +This is useful if you want to integrate `cargo test` into other tooling. + +We can invert our test's failure with another attribute: `should_panic`: + +```rust +#[test] +#[should_panic] +fn it_works() { + assert!(false); +} +``` + +This test will now succeed if we `panic!` and fail if we complete. Let's try it: + +```bash +$ cargo test + Compiling adder v0.0.1 (file:///home/you/projects/adder) + Running target/adder-91b3e234d4ed382a + +running 1 test +test it_works ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests adder + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` + +Rust provides another macro, `assert_eq!`, that compares two arguments for +equality: + +```rust +#[test] +#[should_panic] +fn it_works() { + assert_eq!("Hello", "world"); +} +``` + +Does this test pass or fail? Because of the `should_panic` attribute, it +passes: + +```bash +$ cargo test + Compiling adder v0.0.1 (file:///home/you/projects/adder) + Running target/adder-91b3e234d4ed382a + +running 1 test +test it_works ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests adder + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` + +`should_panic` tests can be fragile, as it's hard to guarantee that the test +didn't fail for an unexpected reason. To help with this, an optional `expected` +parameter can be added to the `should_panic` attribute. The test harness will +make sure that the failure message contains the provided text. A safer version +of the example above would be: + +``` +#[test] +#[should_panic(expected = "assertion failed")] +fn it_works() { + assert_eq!("Hello", "world"); +} +``` + +That's all there is to the basics! Let's write one 'real' test: + +```{rust,ignore} +pub fn add_two(a: i32) -> i32 { + a + 2 +} + +#[test] +fn it_works() { + assert_eq!(4, add_two(2)); +} +``` + +This is a very common use of `assert_eq!`: call some function with +some known arguments and compare it to the expected output. + +# The `test` module + +There is one way in which our existing example is not idiomatic: it's +missing the test module. The idiomatic way of writing our example +looks like this: + +```{rust,ignore} +pub fn add_two(a: i32) -> i32 { + a + 2 +} + +#[cfg(test)] +mod test { + use super::add_two; + + #[test] + fn it_works() { + assert_eq!(4, add_two(2)); + } +} +``` + +There's a few changes here. The first is the introduction of a `mod test` with +a `cfg` attribute. The module allows us to group all of our tests together, and +to also define helper functions if needed, that don't become a part of the rest +of our crate. The `cfg` attribute only compiles our test code if we're +currently trying to run the tests. This can save compile time, and also ensures +that our tests are entirely left out of a normal build. + +The second change is the `use` declaration. Because we're in an inner module, +we need to bring our test function into scope. This can be annoying if you have +a large module, and so this is a common use of the `glob` feature. Let's change +our `src/lib.rs` to make use of it: + +```{rust,ignore} + +pub fn add_two(a: i32) -> i32 { + a + 2 +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn it_works() { + assert_eq!(4, add_two(2)); + } +} +``` + +Note the different `use` line. Now we run our tests: + +```bash +$ cargo test + Updating registry `https://github.com/rust-lang/crates.io-index` + Compiling adder v0.0.1 (file:///home/you/projects/adder) + Running target/adder-91b3e234d4ed382a + +running 1 test +test test::it_works ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests adder + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` + +It works! + +The current convention is to use the `test` module to hold your "unit-style" +tests. Anything that just tests one small bit of functionality makes sense to +go here. But what about "integration-style" tests instead? For that, we have +the `tests` directory + +# The `tests` directory + +To write an integration test, let's make a `tests` directory, and +put a `tests/lib.rs` file inside, with this as its contents: + +```{rust,ignore} +extern crate adder; + +#[test] +fn it_works() { + assert_eq!(4, adder::add_two(2)); +} +``` + +This looks similar to our previous tests, but slightly different. We now have +an `extern crate adder` at the top. This is because the tests in the `tests` +directory are an entirely separate crate, and so we need to import our library. +This is also why `tests` is a suitable place to write integration-style tests: +they use the library like any other consumer of it would. + +Let's run them: + +```bash +$ cargo test + Compiling adder v0.0.1 (file:///home/you/projects/adder) + Running target/adder-91b3e234d4ed382a + +running 1 test +test test::it_works ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Running target/lib-c18e7d3494509e74 + +running 1 test +test it_works ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests adder + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` + +Now we have three sections: our previous test is also run, as well as our new +one. + +That's all there is to the `tests` directory. The `test` module isn't needed +here, since the whole thing is focused on tests. + +Let's finally check out that third section: documentation tests. + +# Documentation tests + +Nothing is better than documentation with examples. Nothing is worse than +examples that don't actually work, because the code has changed since the +documentation has been written. To this end, Rust supports automatically +running examples in your documentation. Here's a fleshed-out `src/lib.rs` +with examples: + +```{rust,ignore} +//! The `adder` crate provides functions that add numbers to other numbers. +//! +//! # Examples +//! +//! ``` +//! assert_eq!(4, adder::add_two(2)); +//! ``` + +/// This function adds two to its argument. +/// +/// # Examples +/// +/// ``` +/// use adder::add_two; +/// +/// assert_eq!(4, add_two(2)); +/// ``` +pub fn add_two(a: i32) -> i32 { + a + 2 +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn it_works() { + assert_eq!(4, add_two(2)); + } +} +``` + +Note the module-level documentation with `//!` and the function-level +documentation with `///`. Rust's documentation supports Markdown in comments, +and so triple graves mark code blocks. It is conventional to include the +`# Examples` section, exactly like that, with examples following. + +Let's run the tests again: + +```bash +$ cargo test + Compiling adder v0.0.1 (file:///home/steve/tmp/adder) + Running target/adder-91b3e234d4ed382a + +running 1 test +test test::it_works ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Running target/lib-c18e7d3494509e74 + +running 1 test +test it_works ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests adder + +running 2 tests +test add_two_0 ... ok +test _0 ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured +``` + +Now we have all three kinds of tests running! Note the names of the +documentation tests: the `_0` is generated for the module test, and `add_two_0` +for the function test. These will auto increment with names like `add_two_1` as +you add more examples. + diff --git a/src/doc/trpl/the-stack-and-the-heap.md b/src/doc/trpl/the-stack-and-the-heap.md index e69de29bb2d1d..cc0941bc025aa 100644 --- a/src/doc/trpl/the-stack-and-the-heap.md +++ b/src/doc/trpl/the-stack-and-the-heap.md @@ -0,0 +1,3 @@ +% The Stack and the Heap + +Coming Soon diff --git a/src/doc/trpl/trait-objects.md b/src/doc/trpl/trait-objects.md index e69de29bb2d1d..d008d30597fea 100644 --- a/src/doc/trpl/trait-objects.md +++ b/src/doc/trpl/trait-objects.md @@ -0,0 +1,306 @@ +% Trait Objects + +When code involves polymorphism, there needs to be a mechanism to determine +which specific version is actually run. This is called 'dispatch.' There are +two major forms of dispatch: static dispatch and dynamic dispatch. While Rust +favors static dispatch, it also supports dynamic dispatch through a mechanism +called 'trait objects.' + +## Background + +For the rest of this chapter, we'll need a trait and some implementations. +Let's make a simple one, `Foo`. It has one method that is expected to return a +`String`. + +```rust +trait Foo { + fn method(&self) -> String; +} +``` + +We'll also implement this trait for `u8` and `String`: + +```rust +# trait Foo { fn method(&self) -> String; } +impl Foo for u8 { + fn method(&self) -> String { format!("u8: {}", *self) } +} + +impl Foo for String { + fn method(&self) -> String { format!("string: {}", *self) } +} +``` + + +## Static dispatch + +We can use this trait to perform static dispatch with trait bounds: + +```rust +# trait Foo { fn method(&self) -> String; } +# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } } +# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } } +fn do_something(x: T) { + x.method(); +} + +fn main() { + let x = 5u8; + let y = "Hello".to_string(); + + do_something(x); + do_something(y); +} +``` + +Rust uses 'monomorphization' to perform static dispatch here. This means that +Rust will create a special version of `do_something()` for both `u8` and +`String`, and then replace the call sites with calls to these specialized +functions. In other words, Rust generates something like this: + +```rust +# trait Foo { fn method(&self) -> String; } +# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } } +# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } } +fn do_something_u8(x: u8) { + x.method(); +} + +fn do_something_string(x: String) { + x.method(); +} + +fn main() { + let x = 5u8; + let y = "Hello".to_string(); + + do_something_u8(x); + do_something_string(y); +} +``` + +This has a great upside: static dispatch allows function calls to be +inlined because the callee is known at compile time, and inlining is +the key to good optimization. Static dispatch is fast, but it comes at +a tradeoff: 'code bloat', due to many copies of the same function +existing in the binary, one for each type. + +Furthermore, compilers aren’t perfect and may “optimize” code to become slower. +For example, functions inlined too eagerly will bloat the instruction cache +(cache rules everything around us). This is part of the reason that `#[inline]` +and `#[inline(always)]` should be used carefully, and one reason why using a +dynamic dispatch is sometimes more efficient. + +However, the common case is that it is more efficient to use static dispatch, +and one can always have a thin statically-dispatched wrapper function that does +a dynamic dispatch, but not vice versa, meaning static calls are more flexible. +The standard library tries to be statically dispatched where possible for this +reason. + +## Dynamic dispatch + +Rust provides dynamic dispatch through a feature called 'trait objects.' Trait +objects, like `&Foo` or `Box`, are normal values that store a value of +*any* type that implements the given trait, where the precise type can only be +known at runtime. + +A trait object can be obtained from a pointer to a concrete type that +implements the trait by *casting* it (e.g. `&x as &Foo`) or *coercing* it +(e.g. using `&x` as an argument to a function that takes `&Foo`). + +These trait object coercions and casts also work for pointers like `&mut T` to +`&mut Foo` and `Box` to `Box`, but that's all at the moment. Coercions +and casts are identical. + +This operation can be seen as "erasing" the compiler's knowledge about the +specific type of the pointer, and hence trait objects are sometimes referred to +as "type erasure". + +Coming back to the example above, we can use the same trait to perform dynamic +dispatch with trait objects by casting: + +```rust +# trait Foo { fn method(&self) -> String; } +# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } } +# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } } + +fn do_something(x: &Foo) { + x.method(); +} + +fn main() { + let x = 5u8; + do_something(&x as &Foo); +} +``` + +or by coercing: + +```rust +# trait Foo { fn method(&self) -> String; } +# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } } +# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } } + +fn do_something(x: &Foo) { + x.method(); +} + +fn main() { + let x = "Hello".to_string(); + do_something(&x); +} +``` + +A function that takes a trait object is not specialized to each of the types +that implements `Foo`: only one copy is generated, often (but not always) +resulting in less code bloat. However, this comes at the cost of requiring +slower virtual function calls, and effectively inhibiting any chance of +inlining and related optimisations from occurring. + +### Why pointers? + +Rust does not put things behind a pointer by default, unlike many managed +languages, so types can have different sizes. Knowing the size of the value at +compile time is important for things like passing it as an argument to a +function, moving it about on the stack and allocating (and deallocating) space +on the heap to store it. + +For `Foo`, we would need to have a value that could be at least either a +`String` (24 bytes) or a `u8` (1 byte), as well as any other type for which +dependent crates may implement `Foo` (any number of bytes at all). There's no +way to guarantee that this last point can work if the values are stored without +a pointer, because those other types can be arbitrarily large. + +Putting the value behind a pointer means the size of the value is not relevant +when we are tossing a trait object around, only the size of the pointer itself. + +### Representation + +The methods of the trait can be called on a trait object via a special record +of function pointers traditionally called a 'vtable' (created and managed by +the compiler). + +Trait objects are both simple and complicated: their core representation and +layout is quite straight-forward, but there are some curly error messages and +surprising behaviors to discover. + +Let's start simple, with the runtime representation of a trait object. The +`std::raw` module contains structs with layouts that are the same as the +complicated built-in types, [including trait objects][stdraw]: + +```rust +# mod foo { +pub struct TraitObject { + pub data: *mut (), + pub vtable: *mut (), +} +# } +``` + +[stdraw]: ../std/raw/struct.TraitObject.html + +That is, a trait object like `&Foo` consists of a "data" pointer and a "vtable" +pointer. + +The data pointer addresses the data (of some unknown type `T`) that the trait +object is storing, and the vtable pointer points to the vtable ("virtual method +table") corresponding to the implementation of `Foo` for `T`. + + +A vtable is essentially a struct of function pointers, pointing to the concrete +piece of machine code for each method in the implementation. A method call like +`trait_object.method()` will retrieve the correct pointer out of the vtable and +then do a dynamic call of it. For example: + +```{rust,ignore} +struct FooVtable { + destructor: fn(*mut ()), + size: usize, + align: usize, + method: fn(*const ()) -> String, +} + +// u8: + +fn call_method_on_u8(x: *const ()) -> String { + // the compiler guarantees that this function is only called + // with `x` pointing to a u8 + let byte: &u8 = unsafe { &*(x as *const u8) }; + + byte.method() +} + +static Foo_for_u8_vtable: FooVtable = FooVtable { + destructor: /* compiler magic */, + size: 1, + align: 1, + + // cast to a function pointer + method: call_method_on_u8 as fn(*const ()) -> String, +}; + + +// String: + +fn call_method_on_String(x: *const ()) -> String { + // the compiler guarantees that this function is only called + // with `x` pointing to a String + let string: &String = unsafe { &*(x as *const String) }; + + string.method() +} + +static Foo_for_String_vtable: FooVtable = FooVtable { + destructor: /* compiler magic */, + // values for a 64-bit computer, halve them for 32-bit ones + size: 24, + align: 8, + + method: call_method_on_String as fn(*const ()) -> String, +}; +``` + +The `destructor` field in each vtable points to a function that will clean up +any resources of the vtable's type, for `u8` it is trivial, but for `String` it +will free the memory. This is necessary for owning trait objects like +`Box`, which need to clean-up both the `Box` allocation as well as the +internal type when they go out of scope. The `size` and `align` fields store +the size of the erased type, and its alignment requirements; these are +essentially unused at the moment since the information is embedded in the +destructor, but will be used in the future, as trait objects are progressively +made more flexible. + +Suppose we've got some values that implement `Foo`, then the explicit form of +construction and use of `Foo` trait objects might look a bit like (ignoring the +type mismatches: they're all just pointers anyway): + +```{rust,ignore} +let a: String = "foo".to_string(); +let x: u8 = 1; + +// let b: &Foo = &a; +let b = TraitObject { + // store the data + data: &a, + // store the methods + vtable: &Foo_for_String_vtable +}; + +// let y: &Foo = x; +let y = TraitObject { + // store the data + data: &x, + // store the methods + vtable: &Foo_for_u8_vtable +}; + +// b.method(); +(b.vtable.method)(b.data); + +// y.method(); +(y.vtable.method)(y.data); +``` + +If `b` or `y` were owning trait objects (`Box`), there would be a +`(b.vtable.destructor)(b.data)` (respectively `y`) call when they went out of +scope. diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index e69de29bb2d1d..2986de4179b89 100644 --- a/src/doc/trpl/traits.md +++ b/src/doc/trpl/traits.md @@ -0,0 +1,508 @@ +% Traits + +Do you remember the `impl` keyword, used to call a function with method +syntax? + +```{rust} +# #![feature(core)] +struct Circle { + x: f64, + y: f64, + radius: f64, +} + +impl Circle { + fn area(&self) -> f64 { + std::f64::consts::PI * (self.radius * self.radius) + } +} +``` + +Traits are similar, except that we define a trait with just the method +signature, then implement the trait for that struct. Like this: + +```{rust} +# #![feature(core)] +struct Circle { + x: f64, + y: f64, + radius: f64, +} + +trait HasArea { + fn area(&self) -> f64; +} + +impl HasArea for Circle { + fn area(&self) -> f64 { + std::f64::consts::PI * (self.radius * self.radius) + } +} +``` + +As you can see, the `trait` block looks very similar to the `impl` block, +but we don't define a body, just a type signature. When we `impl` a trait, +we use `impl Trait for Item`, rather than just `impl Item`. + +So what's the big deal? Remember the error we were getting with our generic +`inverse` function? + +```text +error: binary operation `==` cannot be applied to type `T` +``` + +We can use traits to constrain our generics. Consider this function, which +does not compile, and gives us a similar error: + +```{rust,ignore} +fn print_area(shape: T) { + println!("This shape has an area of {}", shape.area()); +} +``` + +Rust complains: + +```text +error: type `T` does not implement any method in scope named `area` +``` + +Because `T` can be any type, we can't be sure that it implements the `area` +method. But we can add a *trait constraint* to our generic `T`, ensuring +that it does: + +```{rust} +# trait HasArea { +# fn area(&self) -> f64; +# } +fn print_area(shape: T) { + println!("This shape has an area of {}", shape.area()); +} +``` + +The syntax `` means `any type that implements the HasArea trait`. +Because traits define function type signatures, we can be sure that any type +which implements `HasArea` will have an `.area()` method. + +Here's an extended example of how this works: + +```{rust} +# #![feature(core)] +trait HasArea { + fn area(&self) -> f64; +} + +struct Circle { + x: f64, + y: f64, + radius: f64, +} + +impl HasArea for Circle { + fn area(&self) -> f64 { + std::f64::consts::PI * (self.radius * self.radius) + } +} + +struct Square { + x: f64, + y: f64, + side: f64, +} + +impl HasArea for Square { + fn area(&self) -> f64 { + self.side * self.side + } +} + +fn print_area(shape: T) { + println!("This shape has an area of {}", shape.area()); +} + +fn main() { + let c = Circle { + x: 0.0f64, + y: 0.0f64, + radius: 1.0f64, + }; + + let s = Square { + x: 0.0f64, + y: 0.0f64, + side: 1.0f64, + }; + + print_area(c); + print_area(s); +} +``` + +This program outputs: + +```text +This shape has an area of 3.141593 +This shape has an area of 1 +``` + +As you can see, `print_area` is now generic, but also ensures that we +have passed in the correct types. If we pass in an incorrect type: + +```{rust,ignore} +print_area(5); +``` + +We get a compile-time error: + +```text +error: failed to find an implementation of trait main::HasArea for int +``` + +So far, we've only added trait implementations to structs, but you can +implement a trait for any type. So technically, we _could_ implement +`HasArea` for `i32`: + +```{rust} +trait HasArea { + fn area(&self) -> f64; +} + +impl HasArea for i32 { + fn area(&self) -> f64 { + println!("this is silly"); + + *self as f64 + } +} + +5.area(); +``` + +It is considered poor style to implement methods on such primitive types, even +though it is possible. + +This may seem like the Wild West, but there are two other restrictions around +implementing traits that prevent this from getting out of hand. First, traits +must be `use`d in any scope where you wish to use the trait's method. So for +example, this does not work: + +```{rust,ignore} +mod shapes { + use std::f64::consts; + + trait HasArea { + fn area(&self) -> f64; + } + + struct Circle { + x: f64, + y: f64, + radius: f64, + } + + impl HasArea for Circle { + fn area(&self) -> f64 { + consts::PI * (self.radius * self.radius) + } + } +} + +fn main() { + let c = shapes::Circle { + x: 0.0f64, + y: 0.0f64, + radius: 1.0f64, + }; + + println!("{}", c.area()); +} +``` + +Now that we've moved the structs and traits into their own module, we get an +error: + +```text +error: type `shapes::Circle` does not implement any method in scope named `area` +``` + +If we add a `use` line right above `main` and make the right things public, +everything is fine: + +```{rust} +# #![feature(core)] +mod shapes { + use std::f64::consts; + + pub trait HasArea { + fn area(&self) -> f64; + } + + pub struct Circle { + pub x: f64, + pub y: f64, + pub radius: f64, + } + + impl HasArea for Circle { + fn area(&self) -> f64 { + consts::PI * (self.radius * self.radius) + } + } +} + +use shapes::HasArea; + +fn main() { + let c = shapes::Circle { + x: 0.0f64, + y: 0.0f64, + radius: 1.0f64, + }; + + println!("{}", c.area()); +} +``` + +This means that even if someone does something bad like add methods to `int`, +it won't affect you, unless you `use` that trait. + +There's one more restriction on implementing traits. Either the trait or the +type you're writing the `impl` for must be inside your crate. So, we could +implement the `HasArea` type for `i32`, because `HasArea` is in our crate. But +if we tried to implement `Float`, a trait provided by Rust, for `i32`, we could +not, because both the trait and the type aren't in our crate. + +One last thing about traits: generic functions with a trait bound use +*monomorphization* (*mono*: one, *morph*: form), so they are statically +dispatched. What's that mean? Check out the chapter on [static and dynamic +dispatch](static-and-dynamic-dispatch.html) for more. + +## Multiple trait bounds + +You’ve seen that you can bound a generic type parameter with a trait: + +```rust +fn foo(x: T) { + x.clone(); +} +``` + +If you need more than one bound, you can use `+`: + +```rust +use std::fmt::Debug; + +fn foo(x: T) { + x.clone(); + println!("{:?}", x); +} +``` + +`T` now needs to be both `Clone` as well as `Debug`. + +## Where clause + +Writing functions with only a few generic types and a small number of trait +bounds isn't too bad, but as the number increases, the syntax gets increasingly +awkward: + +``` +use std::fmt::Debug; + +fn foo(x: T, y: K) { + x.clone(); + y.clone(); + println!("{:?}", y); +} +``` + +The name of the function is on the far left, and the parameter list is on the +far right. The bounds are getting in the way. + +Rust has a solution, and it's called a '`where` clause': + +``` +use std::fmt::Debug; + +fn foo(x: T, y: K) { + x.clone(); + y.clone(); + println!("{:?}", y); +} + +fn bar(x: T, y: K) where T: Clone, K: Clone + Debug { + x.clone(); + y.clone(); + println!("{:?}", y); +} + +fn main() { + foo("Hello", "world"); + bar("Hello", "workd"); +} +``` + +`foo()` uses the syntax we showed earlier, and `bar()` uses a `where` clause. +All you need to do is leave off the bounds when defining your type parameters, +and then add `where` after the parameter list. For longer lists, whitespace can +be added: + +``` +use std::fmt::Debug; + +fn bar(x: T, y: K) + where T: Clone, + K: Clone + Debug { + + x.clone(); + y.clone(); + println!("{:?}", y); +} +``` + +This flexibility can add clarity in complex situations. + +`where` is also more powerful than the simpler syntax. For example: + +``` +trait ConvertTo { + fn convert(&self) -> Output; +} + +impl ConvertTo for i32 { + fn convert(&self) -> i64 { *self as i64 } +} + +// can be called with T == i32 +fn normal>(x: &T) -> i64 { + x.convert() +} + +// can be called with T == i64 +fn inverse() -> T + // this is using ConvertTo as if it were "ConvertFrom" + where i32: ConvertTo { + 1i32.convert() +} +``` + +This shows off the additional feature of `where` clauses: they allow bounds +where the left-hand side is an arbitrary type (`i32` in this case), not just a +plain type parameter (like `T`). + +## Our `inverse` Example + +Back in [Generics](generics.html), we were trying to write code like this: + +```{rust,ignore} +fn inverse(x: T) -> Result { + if x == 0.0 { return Err("x cannot be zero!".to_string()); } + + Ok(1.0 / x) +} +``` + +If we try to compile it, we get this error: + +```text +error: binary operation `==` cannot be applied to type `T` +``` + +This is because `T` is too generic: we don't know if a random `T` can be +compared. For that, we can use trait bounds. It doesn't quite work, but try +this: + +```{rust,ignore} +fn inverse(x: T) -> Result { + if x == 0.0 { return Err("x cannot be zero!".to_string()); } + + Ok(1.0 / x) +} +``` + +You should get this error: + +```text +error: mismatched types: + expected `T`, + found `_` +(expected type parameter, + found floating-point variable) +``` + +So this won't work. While our `T` is `PartialEq`, we expected to have another `T`, +but instead, we found a floating-point variable. We need a different bound. `Float` +to the rescue: + +``` +# #![feature(std_misc)] +use std::num::Float; + +fn inverse(x: T) -> Result { + if x == Float::zero() { return Err("x cannot be zero!".to_string()) } + + let one: T = Float::one(); + Ok(one / x) +} +``` + +We've had to replace our generic `0.0` and `1.0` with the appropriate methods +from the `Float` trait. Both `f32` and `f64` implement `Float`, so our function +works just fine: + +``` +# #![feature(std_misc)] +# use std::num::Float; +# fn inverse(x: T) -> Result { +# if x == Float::zero() { return Err("x cannot be zero!".to_string()) } +# let one: T = Float::one(); +# Ok(one / x) +# } +println!("the inverse of {} is {:?}", 2.0f32, inverse(2.0f32)); +println!("the inverse of {} is {:?}", 2.0f64, inverse(2.0f64)); + +println!("the inverse of {} is {:?}", 0.0f32, inverse(0.0f32)); +println!("the inverse of {} is {:?}", 0.0f64, inverse(0.0f64)); +``` + +## Default methods + +There's one last feature of traits we should cover: default methods. It's +easiest just to show an example: + +```rust +trait Foo { + fn bar(&self); + + fn baz(&self) { println!("We called baz."); } +} +``` + +Implementors of the `Foo` trait need to implement `bar()`, but they don't +need to implement `baz()`. They'll get this default behavior. They can +override the default if they so choose: + +```rust +# trait Foo { +# fn bar(&self); +# fn baz(&self) { println!("We called baz."); } +# } +struct UseDefault; + +impl Foo for UseDefault { + fn bar(&self) { println!("We called bar."); } +} + +struct OverrideDefault; + +impl Foo for OverrideDefault { + fn bar(&self) { println!("We called bar."); } + + fn baz(&self) { println!("Override baz!"); } +} + +let default = UseDefault; +default.baz(); // prints "We called baz." + +let over = OverrideDefault; +over.baz(); // prints "Override baz!" +``` diff --git a/src/doc/trpl/tuple-structs.md b/src/doc/trpl/tuple-structs.md index e69de29bb2d1d..8fba658fba2cd 100644 --- a/src/doc/trpl/tuple-structs.md +++ b/src/doc/trpl/tuple-structs.md @@ -0,0 +1,56 @@ +% Tuple Structs + +Rust has another data type that's like a hybrid between a tuple and a struct, +called a *tuple struct*. Tuple structs do have a name, but their fields don't: + +```{rust} +struct Color(i32, i32, i32); +struct Point(i32, i32, i32); +``` + +These two will not be equal, even if they have the same values: + +```{rust} +# struct Color(i32, i32, i32); +# struct Point(i32, i32, i32); +let black = Color(0, 0, 0); +let origin = Point(0, 0, 0); +``` + +It is almost always better to use a struct than a tuple struct. We would write +`Color` and `Point` like this instead: + +```{rust} +struct Color { + red: i32, + blue: i32, + green: i32, +} + +struct Point { + x: i32, + y: i32, + z: i32, +} +``` + +Now, we have actual names, rather than positions. Good names are important, +and with a struct, we have actual names. + +There _is_ one case when a tuple struct is very useful, though, and that's a +tuple struct with only one element. We call this the *newtype* pattern, because +it allows you to create a new type, distinct from that of its contained value +and expressing its own semantic meaning: + +```{rust} +struct Inches(i32); + +let length = Inches(10); + +let Inches(integer_length) = length; +println!("length is {} inches", integer_length); +``` + +As you can see here, you can extract the inner integer type through a +destructuring `let`, as we discussed previously in 'tuples.' In this case, the +`let Inches(integer_length)` assigns `10` to `integer_length`. diff --git a/src/doc/trpl/tuples.md b/src/doc/trpl/tuples.md index e69de29bb2d1d..dd526d05b671e 100644 --- a/src/doc/trpl/tuples.md +++ b/src/doc/trpl/tuples.md @@ -0,0 +1,97 @@ +% Tuples + +The first compound data type we're going to talk about is called the *tuple*. +A tuple is an ordered list of fixed size. Like this: + +```rust +let x = (1, "hello"); +``` + +The parentheses and commas form this two-length tuple. Here's the same code, but +with the type annotated: + +```rust +let x: (i32, &str) = (1, "hello"); +``` + +As you can see, the type of a tuple looks just like the tuple, but with each +position having a type name rather than the value. Careful readers will also +note that tuples are heterogeneous: we have an `i32` and a `&str` in this tuple. +You have briefly seen `&str` used as a type before, and we'll discuss the +details of strings later. In systems programming languages, strings are a bit +more complex than in other languages. For now, just read `&str` as a *string +slice*, and we'll learn more soon. + +You can access the fields in a tuple through a *destructuring let*. Here's +an example: + +```rust +let (x, y, z) = (1, 2, 3); + +println!("x is {}", x); +``` + +Remember before when I said the left-hand side of a `let` statement was more +powerful than just assigning a binding? Here we are. We can put a pattern on +the left-hand side of the `let`, and if it matches up to the right-hand side, +we can assign multiple bindings at once. In this case, `let` "destructures," +or "breaks up," the tuple, and assigns the bits to three bindings. + +This pattern is very powerful, and we'll see it repeated more later. + +There are also a few things you can do with a tuple as a whole, without +destructuring. You can assign one tuple into another, if they have the same +contained types and [arity]. Tuples have the same arity when they have the same +length. + +```rust +let mut x = (1, 2); // x: (i32, i32) +let y = (2, 3); // y: (i32, i32) + +x = y; +``` + +You can also check for equality with `==`. Again, this will only compile if the +tuples have the same type. + +```rust +let x = (1, 2, 3); +let y = (2, 2, 4); + +if x == y { + println!("yes"); +} else { + println!("no"); +} +``` + +This will print `no`, because some of the values aren't equal. + +Note that the order of the values is considered when checking for equality, +so the following example will also print `no`. + +```rust +let x = (1, 2, 3); +let y = (2, 1, 3); + +if x == y { + println!("yes"); +} else { + println!("no"); +} +``` + +One other use of tuples is to return multiple values from a function: + +```rust +fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) } + +fn main() { + let (x, y) = next_two(5); + println!("x, y = {}, {}", x, y); +} +``` + +Even though Rust functions can only return one value, a tuple *is* one value, +that happens to be made up of more than one value. You can also see in this +example how you can destructure a pattern returned by a function, as well. diff --git a/src/doc/trpl/type-aliases.md b/src/doc/trpl/type-aliases.md index e69de29bb2d1d..fffa0ae1383c2 100644 --- a/src/doc/trpl/type-aliases.md +++ b/src/doc/trpl/type-aliases.md @@ -0,0 +1,3 @@ +% `type` Aliases + +Coming soon diff --git a/src/doc/trpl/ufcs.md b/src/doc/trpl/ufcs.md index e69de29bb2d1d..6b9a417c43944 100644 --- a/src/doc/trpl/ufcs.md +++ b/src/doc/trpl/ufcs.md @@ -0,0 +1,3 @@ +% Universal Function Call Syntax + +Coming soon diff --git a/src/doc/trpl/unsafe-code.md b/src/doc/trpl/unsafe-code.md index e69de29bb2d1d..b641f2b104a72 100644 --- a/src/doc/trpl/unsafe-code.md +++ b/src/doc/trpl/unsafe-code.md @@ -0,0 +1,183 @@ +% Unsafe Code + +# Introduction + +Rust aims to provide safe abstractions over the low-level details of +the CPU and operating system, but sometimes one needs to drop down and +write code at that level. This guide aims to provide an overview of +the dangers and power one gets with Rust's unsafe subset. + +Rust provides an escape hatch in the form of the `unsafe { ... }` +block which allows the programmer to dodge some of the compiler's +checks and do a wide range of operations, such as: + +- dereferencing [raw pointers](#raw-pointers) +- calling a function via FFI ([covered by the FFI guide](ffi.html)) +- casting between types bitwise (`transmute`, aka "reinterpret cast") +- [inline assembly](#inline-assembly) + +Note that an `unsafe` block does not relax the rules about lifetimes +of `&` and the freezing of borrowed data. + +Any use of `unsafe` is the programmer saying "I know more than you" to +the compiler, and, as such, the programmer should be very sure that +they actually do know more about why that piece of code is valid. In +general, one should try to minimize the amount of unsafe code in a +code base; preferably by using the bare minimum `unsafe` blocks to +build safe interfaces. + +> **Note**: the low-level details of the Rust language are still in +> flux, and there is no guarantee of stability or backwards +> compatibility. In particular, there may be changes that do not cause +> compilation errors, but do cause semantic changes (such as invoking +> undefined behaviour). As such, extreme care is required. + +# Pointers + +## References + +One of Rust's biggest features is memory safety. This is achieved in +part via [the ownership system](ownership.html), which is how the +compiler can guarantee that every `&` reference is always valid, and, +for example, never pointing to freed memory. + +These restrictions on `&` have huge advantages. However, they also +constrain how we can use them. For example, `&` doesn't behave +identically to C's pointers, and so cannot be used for pointers in +foreign function interfaces (FFI). Additionally, both immutable (`&`) +and mutable (`&mut`) references have some aliasing and freezing +guarantees, required for memory safety. + +In particular, if you have an `&T` reference, then the `T` must not be +modified through that reference or any other reference. There are some +standard library types, e.g. `Cell` and `RefCell`, that provide inner +mutability by replacing compile time guarantees with dynamic checks at +runtime. + +An `&mut` reference has a different constraint: when an object has an +`&mut T` pointing into it, then that `&mut` reference must be the only +such usable path to that object in the whole program. That is, an +`&mut` cannot alias with any other references. + +Using `unsafe` code to incorrectly circumvent and violate these +restrictions is undefined behaviour. For example, the following +creates two aliasing `&mut` pointers, and is invalid. + +``` +use std::mem; +let mut x: u8 = 1; + +let ref_1: &mut u8 = &mut x; +let ref_2: &mut u8 = unsafe { mem::transmute(&mut *ref_1) }; + +// oops, ref_1 and ref_2 point to the same piece of data (x) and are +// both usable +*ref_1 = 10; +*ref_2 = 20; +``` + +## Raw pointers + +Rust offers two additional pointer types (*raw pointers*), written as +`*const T` and `*mut T`. They're an approximation of C's `const T*` and `T*` +respectively; indeed, one of their most common uses is for FFI, +interfacing with external C libraries. + +Raw pointers have much fewer guarantees than other pointer types +offered by the Rust language and libraries. For example, they + +- are not guaranteed to point to valid memory and are not even + guaranteed to be non-null (unlike both `Box` and `&`); +- do not have any automatic clean-up, unlike `Box`, and so require + manual resource management; +- are plain-old-data, that is, they don't move ownership, again unlike + `Box`, hence the Rust compiler cannot protect against bugs like + use-after-free; +- lack any form of lifetimes, unlike `&`, and so the compiler cannot + reason about dangling pointers; and +- have no guarantees about aliasing or mutability other than mutation + not being allowed directly through a `*const T`. + +Fortunately, they come with a redeeming feature: the weaker guarantees +mean weaker restrictions. The missing restrictions make raw pointers +appropriate as a building block for implementing things like smart +pointers and vectors inside libraries. For example, `*` pointers are +allowed to alias, allowing them to be used to write shared-ownership +types like reference counted and garbage collected pointers, and even +thread-safe shared memory types (`Rc` and the `Arc` types are both +implemented entirely in Rust). + +There are two things that you are required to be careful about +(i.e. require an `unsafe { ... }` block) with raw pointers: + +- dereferencing: they can have any value: so possible results include + a crash, a read of uninitialised memory, a use-after-free, or + reading data as normal. +- pointer arithmetic via the `offset` [intrinsic](#intrinsics) (or + `.offset` method): this intrinsic uses so-called "in-bounds" + arithmetic, that is, it is only defined behaviour if the result is + inside (or one-byte-past-the-end) of the object from which the + original pointer came. + +The latter assumption allows the compiler to optimize more +effectively. As can be seen, actually *creating* a raw pointer is not +unsafe, and neither is converting to an integer. + +### References and raw pointers + +At runtime, a raw pointer `*` and a reference pointing to the same +piece of data have an identical representation. In fact, an `&T` +reference will implicitly coerce to an `*const T` raw pointer in safe code +and similarly for the `mut` variants (both coercions can be performed +explicitly with, respectively, `value as *const T` and `value as *mut T`). + +Going the opposite direction, from `*const` to a reference `&`, is not +safe. A `&T` is always valid, and so, at a minimum, the raw pointer +`*const T` has to point to a valid instance of type `T`. Furthermore, +the resulting pointer must satisfy the aliasing and mutability laws of +references. The compiler assumes these properties are true for any +references, no matter how they are created, and so any conversion from +raw pointers is asserting that they hold. The programmer *must* +guarantee this. + +The recommended method for the conversion is + +``` +let i: u32 = 1; +// explicit cast +let p_imm: *const u32 = &i as *const u32; +let mut m: u32 = 2; +// implicit coercion +let p_mut: *mut u32 = &mut m; + +unsafe { + let ref_imm: &u32 = &*p_imm; + let ref_mut: &mut u32 = &mut *p_mut; +} +``` + +The `&*x` dereferencing style is preferred to using a `transmute`. +The latter is far more powerful than necessary, and the more +restricted operation is harder to use incorrectly; for example, it +requires that `x` is a pointer (unlike `transmute`). + + + +## Making the unsafe safe(r) + +There are various ways to expose a safe interface around some unsafe +code: + +- store pointers privately (i.e. not in public fields of public + structs), so that you can see and control all reads and writes to + the pointer in one place. +- use `assert!()` a lot: since you can't rely on the protection of the + compiler & type-system to ensure that your `unsafe` code is correct + at compile-time, use `assert!()` to verify that it is doing the + right thing at run-time. +- implement the `Drop` for resource clean-up via a destructor, and use + RAII (Resource Acquisition Is Initialization). This reduces the need + for any manual memory management by users, and automatically ensures + that clean-up is always run, even when the thread panics. +- ensure that any data stored behind a raw pointer is destroyed at the + appropriate time. diff --git a/src/doc/trpl/unsized-types.md b/src/doc/trpl/unsized-types.md index e69de29bb2d1d..f307f23f0116a 100644 --- a/src/doc/trpl/unsized-types.md +++ b/src/doc/trpl/unsized-types.md @@ -0,0 +1,3 @@ +% Unsized Types + +Coming Soon! diff --git a/src/doc/trpl/variable-bindings.md b/src/doc/trpl/variable-bindings.md index e69de29bb2d1d..88babd8659c2b 100644 --- a/src/doc/trpl/variable-bindings.md +++ b/src/doc/trpl/variable-bindings.md @@ -0,0 +1,161 @@ +% Variable Bindings + +The first thing we'll learn about are *variable bindings*. They look like this: + +```{rust} +fn main() { + let x = 5; +} +``` + +Putting `fn main() {` in each example is a bit tedious, so we'll leave that out +in the future. If you're following along, make sure to edit your `main()` +function, rather than leaving it off. Otherwise, you'll get an error. + +In many languages, this is called a *variable*. But Rust's variable bindings +have a few tricks up their sleeves. Rust has a very powerful feature called +*pattern matching* that we'll get into detail with later, but the left +hand side of a `let` expression is a full pattern, not just a variable name. +This means we can do things like: + +```{rust} +let (x, y) = (1, 2); +``` + +After this expression is evaluated, `x` will be one, and `y` will be two. +Patterns are really powerful, but this is about all we can do with them so far. +So let's just keep this in the back of our minds as we go forward. + +Rust is a statically typed language, which means that we specify our types up +front. So why does our first example compile? Well, Rust has this thing called +*type inference*. If it can figure out what the type of something is, Rust +doesn't require you to actually type it out. + +We can add the type if we want to, though. Types come after a colon (`:`): + +```{rust} +let x: i32 = 5; +``` + +If I asked you to read this out loud to the rest of the class, you'd say "`x` +is a binding with the type `i32` and the value `five`." + +In this case we chose to represent `x` as a 32-bit signed integer. Rust has +many different primitive integer types. They begin with `i` for signed integers +and `u` for unsigned integers. The possible integer sizes are 8, 16, 32, and 64 +bits. + +In future examples, we may annotate the type in a comment. The examples will +look like this: + +```{rust} +fn main() { + let x = 5; // x: i32 +} +``` + +Note the similarities between this annotation and the syntax you use with `let`. +Including these kinds of comments is not idiomatic Rust, but we'll occasionally +include them to help you understand what the types that Rust infers are. + +By default, bindings are *immutable*. This code will not compile: + +```{ignore} +let x = 5; +x = 10; +``` + +It will give you this error: + +```text +error: re-assignment of immutable variable `x` + x = 10; + ^~~~~~~ +``` + +If you want a binding to be mutable, you can use `mut`: + +```{rust} +let mut x = 5; // mut x: i32 +x = 10; +``` + +There is no single reason that bindings are immutable by default, but we can +think about it through one of Rust's primary focuses: safety. If you forget to +say `mut`, the compiler will catch it, and let you know that you have mutated +something you may not have intended to mutate. If bindings were mutable by +default, the compiler would not be able to tell you this. If you _did_ intend +mutation, then the solution is quite easy: add `mut`. + +There are other good reasons to avoid mutable state when possible, but they're +out of the scope of this guide. In general, you can often avoid explicit +mutation, and so it is preferable in Rust. That said, sometimes, mutation is +what you need, so it's not verboten. + +Let's get back to bindings. Rust variable bindings have one more aspect that +differs from other languages: bindings are required to be initialized with a +value before you're allowed to use them. + +Let's try it out. Change your `src/main.rs` file to look like this: + +```{rust} +fn main() { + let x: i32; + + println!("Hello world!"); +} +``` + +You can use `cargo build` on the command line to build it. You'll get a warning, +but it will still print "Hello, world!": + +```text + Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world) +src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)] on by default +src/main.rs:2 let x: i32; + ^ +``` + +Rust warns us that we never use the variable binding, but since we never use it, +no harm, no foul. Things change if we try to actually use this `x`, however. Let's +do that. Change your program to look like this: + +```{rust,ignore} +fn main() { + let x: i32; + + println!("The value of x is: {}", x); +} +``` + +And try to build it. You'll get an error: + +```{bash} +$ cargo build + Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world) +src/main.rs:4:39: 4:40 error: use of possibly uninitialized variable: `x` +src/main.rs:4 println!("The value of x is: {}", x); + ^ +note: in expansion of format_args! +:2:23: 2:77 note: expansion site +:1:1: 3:2 note: in expansion of println! +src/main.rs:4:5: 4:42 note: expansion site +error: aborting due to previous error +Could not compile `hello_world`. +``` + +Rust will not let us use a value that has not been initialized. Next, let's +talk about this stuff we've added to `println!`. + +If you include two curly braces (`{}`, some call them moustaches...) in your +string to print, Rust will interpret this as a request to interpolate some sort +of value. *String interpolation* is a computer science term that means "stick +in the middle of a string." We add a comma, and then `x`, to indicate that we +want `x` to be the value we're interpolating. The comma is used to separate +arguments we pass to functions and macros, if you're passing more than one. + +When you just use the curly braces, Rust will attempt to display the +value in a meaningful way by checking out its type. If you want to specify the +format in a more detailed manner, there are a [wide number of options +available](../std/fmt/index.html). For now, we'll just stick to the default: +integers aren't very complicated to print. diff --git a/src/doc/trpl/vectors.md b/src/doc/trpl/vectors.md index e69de29bb2d1d..cba435233fab8 100644 --- a/src/doc/trpl/vectors.md +++ b/src/doc/trpl/vectors.md @@ -0,0 +1,33 @@ +% Vectors + +A *vector* is a dynamic or "growable" array, implemented as the standard +library type [`Vec`](../std/vec/) (we'll talk about what the `` means +later). Vectors always allocate their data on the heap. Vectors are to slices +what `String` is to `&str`. You can create them with the `vec!` macro: + +```{rust} +let v = vec![1, 2, 3]; // v: Vec +``` + +(Notice that unlike the `println!` macro we've used in the past, we use square +brackets `[]` with `vec!`. Rust allows you to use either in either situation, +this is just convention.) + +There's an alternate form of `vec!` for repeating an initial value: + +``` +let v = vec![0; 10]; // ten zeroes +``` + +You can get the length of, iterate over, and subscript vectors just like +arrays. In addition, (mutable) vectors can grow automatically: + +```{rust} +let mut nums = vec![1, 2, 3]; // mut nums: Vec + +nums.push(4); + +println!("The length of nums is now {}", nums.len()); // Prints 4 +``` + +Vectors have many more useful methods. diff --git a/src/doc/trpl/while-loops.md b/src/doc/trpl/while-loops.md index e69de29bb2d1d..508c4ee117a5f 100644 --- a/src/doc/trpl/while-loops.md +++ b/src/doc/trpl/while-loops.md @@ -0,0 +1,83 @@ +% `while` loops + +The other kind of looping construct in Rust is the `while` loop. It looks like +this: + +```{rust} +let mut x = 5; // mut x: u32 +let mut done = false; // mut done: bool + +while !done { + x += x - 3; + println!("{}", x); + if x % 5 == 0 { done = true; } +} +``` + +`while` loops are the correct choice when you're not sure how many times +you need to loop. + +If you need an infinite loop, you may be tempted to write this: + +```{rust,ignore} +while true { +``` + +However, Rust has a dedicated keyword, `loop`, to handle this case: + +```{rust,ignore} +loop { +``` + +Rust's control-flow analysis treats this construct differently than a +`while true`, since we know that it will always loop. The details of what +that _means_ aren't super important to understand at this stage, but in +general, the more information we can give to the compiler, the better it +can do with safety and code generation, so you should always prefer +`loop` when you plan to loop infinitely. + +## Ending iteration early + +Let's take a look at that `while` loop we had earlier: + +```{rust} +let mut x = 5; +let mut done = false; + +while !done { + x += x - 3; + println!("{}", x); + if x % 5 == 0 { done = true; } +} +``` + +We had to keep a dedicated `mut` boolean variable binding, `done`, to know +when we should exit out of the loop. Rust has two keywords to help us with +modifying iteration: `break` and `continue`. + +In this case, we can write the loop in a better way with `break`: + +```{rust} +let mut x = 5; + +loop { + x += x - 3; + println!("{}", x); + if x % 5 == 0 { break; } +} +``` + +We now loop forever with `loop` and use `break` to break out early. + +`continue` is similar, but instead of ending the loop, goes to the next +iteration. This will only print the odd numbers: + +```{rust} +for x in 0..10 { + if x % 2 == 0 { continue; } + + println!("{}", x); +} +``` + +Both `continue` and `break` are valid in both kinds of loops. From c9454b1a02754b8cdb46fec00241d5fd2171ef9e Mon Sep 17 00:00:00 2001 From: York Xiang Date: Wed, 8 Apr 2015 10:29:11 +0800 Subject: [PATCH 22/62] Update "`let` is used to introduce variables" paragraph --- src/doc/complement-design-faq.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/doc/complement-design-faq.md b/src/doc/complement-design-faq.md index 3edbcbe62c511..0f2c37a5abf83 100644 --- a/src/doc/complement-design-faq.md +++ b/src/doc/complement-design-faq.md @@ -163,13 +163,17 @@ 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 particularly easy to read. -## `let` is used to introduce variables +## Why is `let` used to introduce variables? -`let` not only defines variables, but can do pattern matching. One can also -redeclare immutable variables with `let`. This is useful to avoid unnecessary -`mut` annotations. An interesting historical note is that Rust comes, -syntactically, most closely from ML, which also uses `let` to introduce -bindings. +We don't use the term "variable", instead, we use "variable bindings". The +simplest way for binding is the `let` syntax, other ways including `if let`, +`while let` and `match`. Bindings also exist in function arguments positions. + +Bindings always happen in pattern matching positions, and it's also Rust's way +to declare mutability. One can also redeclare mutability of a binding in +pattern matching. This is useful to avoid unnecessary `mut` annotations. An +interesting historical note is that Rust comes, syntactically, most closely +from ML, which also uses `let` to introduce bindings. See also [a long thread][alt] on renaming `let mut` to `var`. From a329a61b9bf01bfc3f9f7316bb800b2bc8b76382 Mon Sep 17 00:00:00 2001 From: Richo Healey Date: Tue, 7 Apr 2015 00:40:22 -0700 Subject: [PATCH 23/62] alloc: impl fmt::Pointer for Rc, Arc and Box Closes #24091 --- src/liballoc/arc.rs | 7 +++++++ src/liballoc/boxed.rs | 10 +++++++++ src/liballoc/rc.rs | 7 +++++++ src/libcore/ptr.rs | 8 ++++++++ src/libsyntax/ptr.rs | 7 +++++++ src/test/run-pass/fmt-pointer-trait.rs | 28 ++++++++++++++++++++++++++ 6 files changed, 67 insertions(+) create mode 100644 src/test/run-pass/fmt-pointer-trait.rs diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 68bde1476118d..ff176d815916b 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -668,6 +668,13 @@ impl fmt::Debug for Arc { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Pointer for Arc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Pointer::fmt(&*self._ptr, f) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Default for Arc { #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 2801cf38cb755..4468e425a852d 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -275,6 +275,16 @@ impl fmt::Debug for Box { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Pointer for Box { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // It's not possible to extract the inner Uniq directly from the Box, + // instead we cast it to a *const which aliases the Unique + let ptr: *const T = &**self; + fmt::Pointer::fmt(&ptr, f) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Deref for Box { type Target = T; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 56822cfe28a35..67805d10a4a63 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -634,6 +634,13 @@ impl fmt::Debug for Rc { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Pointer for Rc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Pointer::fmt(&*self._ptr, f) + } +} + /// A weak version of `Rc`. /// /// Weak references do not count when determining if the inner value should be diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index ff51e25fcbf25..36b33e7581dd9 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -94,6 +94,7 @@ use mem; use clone::Clone; use intrinsics; use ops::Deref; +use core::fmt; use option::Option::{self, Some, None}; use marker::{PhantomData, Send, Sized, Sync}; use nonzero::NonZero; @@ -570,3 +571,10 @@ impl Deref for Unique { unsafe { mem::transmute(&*self.pointer) } } } + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Pointer for Unique { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Pointer::fmt(&*self.pointer, f) + } +} diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 7e0bcd3e1dc3f..5032cd57eeb37 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -111,6 +111,13 @@ impl Display for P { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Pointer for P { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Pointer::fmt(&self.ptr, f) + } +} + impl Hash for P { fn hash(&self, state: &mut H) { (**self).hash(state); diff --git a/src/test/run-pass/fmt-pointer-trait.rs b/src/test/run-pass/fmt-pointer-trait.rs new file mode 100644 index 0000000000000..be8ecde67836e --- /dev/null +++ b/src/test/run-pass/fmt-pointer-trait.rs @@ -0,0 +1,28 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(libc)] +extern crate libc; +use std::ptr; +use std::rc::Rc; +use std::sync::Arc; + +fn main() { + let p: *const libc::c_void = ptr::null(); + let rc = Rc::new(1usize); + let arc = Arc::new(1usize); + let b = Box::new("hi"); + + let _ = format!("{:p}{:p}{:p}", + rc, arc, b); + + assert_eq!(format!("{:p}", p), + "0x0"); +} From e2ff1881b2c892aab0ed721a1ecdb4309053dcab Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Wed, 8 Apr 2015 13:55:18 +0900 Subject: [PATCH 24/62] Address review comments --- src/librustc_typeck/check/cast.rs | 8 ++++---- src/librustc_typeck/check/mod.rs | 9 +++------ src/test/compile-fail/fat-ptr-cast.rs | 7 ++++++- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 045b88e2357cd..3773ff7078e9c 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -115,12 +115,12 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { } else if t_1.sty == ty::ty_bool { span_err!(fcx.tcx().sess, span, E0054, "cannot cast as `bool`, compare with zero instead"); - } else if t_e_is_float && (t_1_is_scalar || t_1_is_c_enum) && !( - t_1_is_integral || t_1_is_float) { + } else if t_e_is_float && (t_1_is_scalar || t_1_is_c_enum) && + !(t_1_is_integral || t_1_is_float) { // Casts from float must go through an integer cast_through_integer_err(fcx, span, t_1, t_e) - } else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) && !( - t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) { + } else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) && + !(t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) { // Casts to float must go through an integer or boolean cast_through_integer_err(fcx, span, t_1, t_e) } else if t_e_is_c_enum && t_1_is_trivial { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index cab6f76d0271b..4ecef2235a911 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1560,13 +1560,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn type_is_fat_ptr(&self, ty: Ty<'tcx>, span: Span) -> bool { - match ty.sty { - ty::ty_ptr(ty::mt { ty: t, .. }) | - ty::ty_rptr(_, ty::mt { ty: t, .. }) => { - !self.type_is_known_to_be_sized(t, span) - } - _ => false + if let Some(mt) = ty::deref(ty, true) { + return !self.type_is_known_to_be_sized(mt.ty, span); } + false } pub fn register_builtin_bound(&self, diff --git a/src/test/compile-fail/fat-ptr-cast.rs b/src/test/compile-fail/fat-ptr-cast.rs index 839ebbd279a99..ac5969410fc01 100644 --- a/src/test/compile-fail/fat-ptr-cast.rs +++ b/src/test/compile-fail/fat-ptr-cast.rs @@ -10,5 +10,10 @@ fn main() { let a: &[i32] = &[1, 2, 3]; - a as *const [i32] as usize; //~ ERROR cast from fat pointer + let b: Box<[i32]> = Box::new([1, 2, 3]); + let p = a as *const [i32]; + + a as usize; //~ ERROR cast from fat pointer + b as usize; //~ ERROR cast from fat pointer + p as usize; //~ ERROR cast from fat pointer } From 86c5faf42bea29da18c82ab0af29b3a8428c5a44 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 8 Apr 2015 13:55:01 +0200 Subject: [PATCH 25/62] Address review nit by making `map_id` take an `FnMut`. --- src/librustc/middle/region.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 727a1dcdfb31e..5131322dc41ea 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -172,8 +172,8 @@ impl CodeExtent { /// Maps this scope to a potentially new one according to the /// NodeId transformer `f_id`. - pub fn map_id(&self, f_id: F) -> CodeExtent where - F: Fn(ast::NodeId) -> ast::NodeId, + pub fn map_id(&self, mut f_id: F) -> CodeExtent where + F: FnMut(ast::NodeId) -> ast::NodeId, { match *self { CodeExtent::Misc(node_id) => CodeExtent::Misc(f_id(node_id)), From 59e62deac96072369ca91b57cff08dbdcbc1dd70 Mon Sep 17 00:00:00 2001 From: Luke Gallagher Date: Wed, 8 Apr 2015 23:23:43 +1000 Subject: [PATCH 26/62] Add tests for #22289, #22370 and #22384 Closes #22289 Closes #22370 Closes #22384 --- src/test/compile-fail/issue-22289.rs | 13 +++++++++++++ src/test/compile-fail/issue-22370.rs | 18 ++++++++++++++++++ src/test/compile-fail/issue-22384.rs | 18 ++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 src/test/compile-fail/issue-22289.rs create mode 100644 src/test/compile-fail/issue-22370.rs create mode 100644 src/test/compile-fail/issue-22384.rs diff --git a/src/test/compile-fail/issue-22289.rs b/src/test/compile-fail/issue-22289.rs new file mode 100644 index 0000000000000..f4f6aaa94fe29 --- /dev/null +++ b/src/test/compile-fail/issue-22289.rs @@ -0,0 +1,13 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + 0 as &std::any::Any; //~ ERROR non-scalar cast: `i32` as `&core::any::Any` +} diff --git a/src/test/compile-fail/issue-22370.rs b/src/test/compile-fail/issue-22370.rs new file mode 100644 index 0000000000000..4c6652d812c8c --- /dev/null +++ b/src/test/compile-fail/issue-22370.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength + +trait A {} + +fn f(a: &A) {} +//~^ ERROR the type parameter `T` must be explicitly specified in an object type because its default value `Self` references the type `Self` + +fn main() {} diff --git a/src/test/compile-fail/issue-22384.rs b/src/test/compile-fail/issue-22384.rs new file mode 100644 index 0000000000000..368e2483533a4 --- /dev/null +++ b/src/test/compile-fail/issue-22384.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Trait { + fn foo(); +} + +fn main() { + <::foobar as Trait>::foo(); + //~^ ERROR use of undeclared associated type `Copy::foobar` +} From 1e79870770c08973d018e71d309816b970c7abe1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Apr 2015 04:31:51 -0400 Subject: [PATCH 27/62] Modify the ExprUseVisitor to walk each part of an AutoRef, and in particular to treat an AutoUnsize as as kind of "instantaneous" borrow of the value being unsized. This prevents us from feeding uninitialized data. This caused a problem for the eager reborrow of comparison traits, because that wound up introducing a "double AutoRef", which was not being thoroughly checked before but turned out not to type check. Fortunately, we can just remove that "eager reborrow" as it is no longer needed now that `PartialEq` doesn't force both LHS and RHS to have the same type (and even if we did have this problem, the better way would be to lean on introducing a common supertype). --- src/librustc/middle/check_const.rs | 14 +- src/librustc/middle/expr_use_visitor.rs | 173 +++++++++++++++--- src/librustc/middle/mem_categorization.rs | 24 ++- src/librustc_borrowck/borrowck/check_loans.rs | 1 + src/librustc_borrowck/borrowck/mod.rs | 2 + src/librustc_typeck/check/op.rs | 32 +--- src/librustc_typeck/check/regionck.rs | 14 +- ...orrowck-use-uninitialized-in-cast-trait.rs | 20 ++ .../borrowck-use-uninitialized-in-cast.rs | 20 ++ 9 files changed, 226 insertions(+), 74 deletions(-) create mode 100644 src/test/compile-fail/borrowck-use-uninitialized-in-cast-trait.rs create mode 100644 src/test/compile-fail/borrowck-use-uninitialized-in-cast.rs diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index ce011f2561b79..ee9d1e015539e 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -662,7 +662,19 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'tcx> { cmt: mc::cmt<'tcx>, _loan_region: ty::Region, bk: ty::BorrowKind, - loan_cause: euv::LoanCause) { + loan_cause: euv::LoanCause) + { + // Kind of hacky, but we allow Unsafe coercions in constants. + // These occur when we convert a &T or *T to a *U, as well as + // when making a thin pointer (e.g., `*T`) into a fat pointer + // (e.g., `*Trait`). + match loan_cause { + euv::LoanCause::AutoUnsafe => { + return; + } + _ => { } + } + let mut cur = &cmt; let mut is_interior = false; loop { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 2fa9c7c8fbebb..18e634a2dd630 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -99,6 +99,7 @@ pub enum LoanCause { ClosureCapture(Span), AddrOf, AutoRef, + AutoUnsafe, RefBinding, OverloadedOperator, ClosureInvocation, @@ -800,18 +801,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { return_if_err!(self.mc.cat_expr_unadjusted(expr)); self.delegate_consume(expr.id, expr.span, cmt_unadjusted); } - ty::AdjustDerefRef(ty::AutoDerefRef { - autoref: ref opt_autoref, - autoderefs: n - }) => { - self.walk_autoderefs(expr, n); - - match *opt_autoref { - None => { } - Some(ref r) => { - self.walk_autoref(expr, r, n); - } - } + ty::AdjustDerefRef(ref adj) => { + self.walk_autoderefref(expr, adj); } } } @@ -852,39 +843,165 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } } + fn walk_autoderefref(&mut self, + expr: &ast::Expr, + adj: &ty::AutoDerefRef<'tcx>) { + debug!("walk_autoderefref expr={} adj={}", + expr.repr(self.tcx()), + adj.repr(self.tcx())); + + self.walk_autoderefs(expr, adj.autoderefs); + + // Weird hacky special case: AutoUnsizeUniq, which converts + // from a ~T to a ~Trait etc, always comes in a stylized + // fashion. In particular, we want to consume the ~ pointer + // being dereferenced, not the dereferenced content (as the + // content is, at least for upcasts, unsized). + match adj.autoref { + Some(ty::AutoUnsizeUniq(_)) => { + assert!(adj.autoderefs == 1, + format!("Expected exactly 1 deref with Uniq AutoRefs, found: {}", + adj.autoderefs)); + let cmt_unadjusted = + return_if_err!(self.mc.cat_expr_unadjusted(expr)); + self.delegate_consume(expr.id, expr.span, cmt_unadjusted); + return; + } + _ => { } + } + + let autoref = adj.autoref.as_ref(); + let cmt_derefd = return_if_err!( + self.mc.cat_expr_autoderefd(expr, adj.autoderefs)); + self.walk_autoref(expr, &cmt_derefd, autoref); + } + + /// Walks the autoref `opt_autoref` applied to the autoderef'd + /// `expr`. `cmt_derefd` is the mem-categorized form of `expr` + /// after all relevant autoderefs have occurred. Because AutoRefs + /// can be recursive, this function is recursive: it first walks + /// deeply all the way down the autoref chain, and then processes + /// the autorefs on the way out. At each point, it returns the + /// `cmt` for the rvalue that will be produced by introduced an + /// autoref. fn walk_autoref(&mut self, expr: &ast::Expr, - autoref: &ty::AutoRef, - n: usize) { - debug!("walk_autoref expr={}", expr.repr(self.tcx())); + cmt_derefd: &mc::cmt<'tcx>, + opt_autoref: Option<&ty::AutoRef<'tcx>>) + -> mc::cmt<'tcx> + { + debug!("walk_autoref(expr.id={} cmt_derefd={} opt_autoref={:?})", + expr.id, + cmt_derefd.repr(self.tcx()), + opt_autoref); + + let autoref = match opt_autoref { + Some(autoref) => autoref, + None => { + // No recursive step here, this is a base case. + return cmt_derefd.clone(); + } + }; match *autoref { - ty::AutoPtr(r, m, _) => { - let cmt_derefd = return_if_err!( - self.mc.cat_expr_autoderefd(expr, n)); - debug!("walk_adjustment: cmt_derefd={}", - cmt_derefd.repr(self.tcx())); + ty::AutoPtr(r, m, ref baseref) => { + let cmt_base = self.walk_autoref_recursively(expr, cmt_derefd, baseref); + + debug!("walk_autoref: expr.id={} cmt_base={}", + expr.id, + cmt_base.repr(self.tcx())); self.delegate.borrow(expr.id, expr.span, - cmt_derefd, + cmt_base, r, ty::BorrowKind::from_mutbl(m), AutoRef); } - ty::AutoUnsize(_) | + + ty::AutoUnsize(_) => { + // Converting a `[T; N]` to `[T]` or `T` to `Trait` + // isn't really a borrow, move, etc, in and of itself. + // Also, no recursive step here, this is a base case. + + // It may seem a bit odd to return the cmt_derefd + // unmodified here, but in fact I think it's the right + // thing to do. Essentially the unsize transformation + // isn't really relevant to the borrowing rules -- + // it's best thought of as a kind of side-modifier to + // the autoref, adding additional data that is + // attached to the pointer that is produced, but not + // affecting the data being borrowed in any other + // way. To see what I mean, consider this example: + // + // fn foo<'a>(&'a self) -> &'a Trait { self } + // + // This is valid because the underlying `self` value + // lives for the lifetime 'a. If we were to treat the + // "unsizing" as e.g. producing an rvalue, that would + // only be valid for the temporary scope, which isn't + // enough to justify the return value, which have the + // lifetime 'a. + // + // Another option would be to add a variant for + // categorization (like downcast) that wraps + // cmt_derefd and represents the unsizing operation. + // But I don't think there is any particular use for + // this (yet). -nmatsakis + return cmt_derefd.clone(); + } + ty::AutoUnsizeUniq(_) => { - assert!(n == 1, format!("Expected exactly 1 deref with Uniq \ - AutoRefs, found: {}", n)); - let cmt_unadjusted = - return_if_err!(self.mc.cat_expr_unadjusted(expr)); - self.delegate_consume(expr.id, expr.span, cmt_unadjusted); + // these are handled via special case above + self.tcx().sess.span_bug(expr.span, "nexpected AutoUnsizeUniq"); } - ty::AutoUnsafe(..) => { + + ty::AutoUnsafe(m, ref baseref) => { + let cmt_base = self.walk_autoref_recursively(expr, cmt_derefd, baseref); + + debug!("walk_autoref: expr.id={} cmt_base={}", + expr.id, + cmt_base.repr(self.tcx())); + + // Converting from a &T to *T (or &mut T to *mut T) is + // treated as borrowing it for the enclosing temporary + // scope. + let r = ty::ReScope(region::CodeExtent::from_node_id(expr.id)); + + self.delegate.borrow(expr.id, + expr.span, + cmt_base, + r, + ty::BorrowKind::from_mutbl(m), + AutoUnsafe); } } + + // Construct the categorization for the result of the autoref. + // This is always an rvalue, since we are producing a new + // (temporary) indirection. + + let adj_ty = + ty::adjust_ty_for_autoref(self.tcx(), + expr.span, + cmt_derefd.ty, + opt_autoref); + + self.mc.cat_rvalue_node(expr.id, expr.span, adj_ty) } + fn walk_autoref_recursively(&mut self, + expr: &ast::Expr, + cmt_derefd: &mc::cmt<'tcx>, + autoref: &Option>>) + -> mc::cmt<'tcx> + { + // Shuffle from a ref to an optional box to an optional ref. + let autoref: Option<&ty::AutoRef<'tcx>> = autoref.as_ref().map(|b| &**b); + self.walk_autoref(expr, cmt_derefd, autoref) + } + + // When this returns true, it means that the expression *is* a // method-call (i.e. via the operator-overload). This true result // also implies that walk_overloaded_operator already took care of diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 85255d04df432..6c7dc61109fb5 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -833,6 +833,15 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { ret } + /// Returns the lifetime of a temporary created by expr with id `id`. + /// This could be `'static` if `id` is part of a constant expression. + pub fn temporary_scope(&self, id: ast::NodeId) -> ty::Region { + match self.typer.temporary_scope(id) { + Some(scope) => ty::ReScope(scope), + None => ty::ReStatic + } + } + pub fn cat_rvalue_node(&self, id: ast::NodeId, span: Span, @@ -848,17 +857,12 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { _ => check_const::NOT_CONST }; + // Compute maximum lifetime of this rvalue. This is 'static if + // we can promote to a constant, otherwise equal to enclosing temp + // lifetime. let re = match qualif & check_const::NON_STATIC_BORROWS { - check_const::PURE_CONST => { - // Constant rvalues get promoted to 'static. - ty::ReStatic - } - _ => { - match self.typer.temporary_scope(id) { - Some(scope) => ty::ReScope(scope), - None => ty::ReStatic - } - } + check_const::PURE_CONST => ty::ReStatic, + _ => self.temporary_scope(id), }; let ret = self.cat_rvalue(id, span, re, expr_ty); debug!("cat_rvalue_node ret {}", ret.repr(self.tcx())); diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index ce7b492c51af1..9776538de3fed 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -542,6 +542,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { euv::OverloadedOperator(..) | euv::AddrOf(..) | euv::AutoRef(..) | + euv::AutoUnsafe(..) | euv::ClosureInvocation(..) | euv::ForLoop(..) | euv::RefBinding(..) | diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index f8da075e4bdc2..c57cbcb929fbc 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -775,6 +775,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { euv::AddrOf | euv::RefBinding | euv::AutoRef | + euv::AutoUnsafe | euv::ForLoop | euv::MatchDiscriminant => { format!("cannot borrow {} as mutable", descr) @@ -822,6 +823,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { BorrowViolation(euv::OverloadedOperator) | BorrowViolation(euv::AddrOf) | BorrowViolation(euv::AutoRef) | + BorrowViolation(euv::AutoUnsafe) | BorrowViolation(euv::RefBinding) | BorrowViolation(euv::MatchDiscriminant) => { "cannot borrow data mutably" diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 49e88dc1483eb..7c1fea4e60f6e 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -20,7 +20,6 @@ use super::{ PreferMutLvalue, structurally_resolved_type, }; -use middle::infer; use middle::traits; use middle::ty::{self, Ty}; use syntax::ast; @@ -314,36 +313,9 @@ fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, let method = match trait_did { Some(trait_did) => { - // We do eager coercions to make using operators - // more ergonomic: - // - // - If the input is of type &'a T (resp. &'a mut T), - // then reborrow it to &'b T (resp. &'b mut T) where - // 'b <= 'a. This makes things like `x == y`, where - // `x` and `y` are both region pointers, work. We - // could also solve this with variance or different - // traits that don't force left and right to have same - // type. - let (adj_ty, adjustment) = match lhs_ty.sty { - ty::ty_rptr(r_in, mt) => { - let r_adj = fcx.infcx().next_region_var(infer::Autoref(lhs_expr.span)); - fcx.mk_subr(infer::Reborrow(lhs_expr.span), r_adj, *r_in); - let adjusted_ty = ty::mk_rptr(fcx.tcx(), fcx.tcx().mk_region(r_adj), mt); - let autoptr = ty::AutoPtr(r_adj, mt.mutbl, None); - let adjustment = ty::AutoDerefRef { autoderefs: 1, autoref: Some(autoptr) }; - (adjusted_ty, adjustment) - } - _ => { - (lhs_ty, ty::AutoDerefRef { autoderefs: 0, autoref: None }) - } - }; - - debug!("adjusted_ty={} adjustment={:?}", - adj_ty.repr(fcx.tcx()), - adjustment); - + let noop = ty::AutoDerefRef { autoderefs: 0, autoref: None }; method::lookup_in_trait_adjusted(fcx, expr.span, Some(lhs_expr), opname, - trait_did, adjustment, adj_ty, Some(other_tys)) + trait_did, noop, lhs_ty, Some(other_tys)) } None => None }; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 9171367468026..9554e6ad8aad3 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1119,8 +1119,8 @@ fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, fn link_autoref(rcx: &Rcx, expr: &ast::Expr, autoderefs: usize, - autoref: &ty::AutoRef) { - + autoref: &ty::AutoRef) +{ debug!("link_autoref(autoref={:?})", autoref); let mc = mc::MemCategorizationContext::new(rcx.fcx); let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs)); @@ -1128,11 +1128,15 @@ fn link_autoref(rcx: &Rcx, match *autoref { ty::AutoPtr(r, m, _) => { - link_region(rcx, expr.span, r, - ty::BorrowKind::from_mutbl(m), expr_cmt); + link_region(rcx, expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt); + } + + ty::AutoUnsafe(m, _) => { + let r = ty::ReScope(CodeExtent::from_node_id(expr.id)); + link_region(rcx, expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt); } - ty::AutoUnsafe(..) | ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {} + ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {} } } diff --git a/src/test/compile-fail/borrowck-use-uninitialized-in-cast-trait.rs b/src/test/compile-fail/borrowck-use-uninitialized-in-cast-trait.rs new file mode 100644 index 0000000000000..796b455f5c70a --- /dev/null +++ b/src/test/compile-fail/borrowck-use-uninitialized-in-cast-trait.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Variation on `borrowck-use-uninitialized-in-cast` in which we do a +// trait cast from an uninitialized source. Issue #20791. + +trait Foo { fn dummy(&self) { } } +impl Foo for i32 { } + +fn main() { + let x: &i32; + let y = x as *const Foo; //~ ERROR use of possibly uninitialized variable: `*x` +} diff --git a/src/test/compile-fail/borrowck-use-uninitialized-in-cast.rs b/src/test/compile-fail/borrowck-use-uninitialized-in-cast.rs new file mode 100644 index 0000000000000..a3d5af80b533b --- /dev/null +++ b/src/test/compile-fail/borrowck-use-uninitialized-in-cast.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that we detect unused values that are cast to other things. +// The problem was specified to casting to `*`, as creating unsafe +// pointers was not being fully checked. Issue #20791. + +// pretty-expanded FIXME #23616 + +fn main() { + let x: &i32; + let y = x as *const i32; //~ ERROR use of possibly uninitialized variable: `*x` +} From 45aa6c8d1bc2f7863c92da6643de4642bb2d83bf Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 4 Apr 2015 00:46:54 +0300 Subject: [PATCH 28/62] Implement reentrant mutexes and make stdio use them write_fmt calls write for each formatted field. The default implementation of write_fmt is used, which will call write on not-yet-locked stdout (and write locking after), therefore making print! in multithreaded environment still interleave contents of two separate prints. This patch implements reentrant mutexes, changes stdio handles to use these mutexes and overrides write_fmt to lock the stdio handle for the whole duration of the call. --- src/libstd/io/stdio.rs | 42 ++-- src/libstd/sync/condvar.rs | 6 +- src/libstd/sync/mod.rs | 13 +- src/libstd/sync/mutex.rs | 6 +- src/libstd/sync/rwlock.rs | 4 +- src/libstd/sys/common/mod.rs | 2 + src/libstd/{sync => sys/common}/poison.rs | 0 src/libstd/sys/common/remutex.rs | 233 ++++++++++++++++++++++ src/libstd/sys/unix/mutex.rs | 48 +++++ src/libstd/sys/unix/sync.rs | 29 ++- src/libstd/sys/windows/mutex.rs | 31 +++ src/libstd/sys/windows/sync.rs | 18 +- src/test/run-pass/atomic-print.rs | 48 +++++ 13 files changed, 446 insertions(+), 34 deletions(-) rename src/libstd/{sync => sys/common}/poison.rs (100%) create mode 100644 src/libstd/sys/common/remutex.rs create mode 100644 src/test/run-pass/atomic-print.rs diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index d361f17cbe41b..2850d92e34d40 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -18,6 +18,7 @@ use io::lazy::Lazy; use io::{self, BufReader, LineWriter}; use sync::{Arc, Mutex, MutexGuard}; use sys::stdio; +use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; /// Stdout used by print! and println! macros thread_local! { @@ -210,7 +211,7 @@ pub struct Stdout { // FIXME: this should be LineWriter or BufWriter depending on the state of // stdout (tty or not). Note that if this is not line buffered it // should also flush-on-panic or some form of flush-on-abort. - inner: Arc>>, + inner: Arc>>>, } /// A locked reference to the a `Stdout` handle. @@ -219,7 +220,7 @@ pub struct Stdout { /// method on `Stdout`. #[stable(feature = "rust1", since = "1.0.0")] pub struct StdoutLock<'a> { - inner: MutexGuard<'a, LineWriter>, + inner: ReentrantMutexGuard<'a, RefCell>>, } /// Constructs a new reference to the standard output of the current process. @@ -231,13 +232,13 @@ pub struct StdoutLock<'a> { /// The returned handle implements the `Write` trait. #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { - static INSTANCE: Lazy>> = lazy_init!(stdout_init); + static INSTANCE: Lazy>>> = lazy_init!(stdout_init); return Stdout { inner: INSTANCE.get().expect("cannot access stdout during shutdown"), }; - fn stdout_init() -> Arc>> { - Arc::new(Mutex::new(LineWriter::new(stdout_raw()))) + fn stdout_init() -> Arc>>> { + Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw())))) } } @@ -264,15 +265,18 @@ impl Write for Stdout { fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.lock().write_all(buf) } - // Don't override write_fmt as it's possible to run arbitrary code during a - // write_fmt, allowing the possibility of a recursive lock (aka deadlock) + fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> { + self.lock().write_fmt(args) + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Write for StdoutLock<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(&buf[..cmp::min(buf.len(), OUT_MAX)]) + self.inner.borrow_mut().write(&buf[..cmp::min(buf.len(), OUT_MAX)]) + } + fn flush(&mut self) -> io::Result<()> { + self.inner.borrow_mut().flush() } - fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } /// A handle to the standard error stream of a process. @@ -280,7 +284,7 @@ impl<'a> Write for StdoutLock<'a> { /// For more information, see `stderr` #[stable(feature = "rust1", since = "1.0.0")] pub struct Stderr { - inner: Arc>, + inner: Arc>>, } /// A locked reference to the a `Stderr` handle. @@ -289,7 +293,7 @@ pub struct Stderr { /// method on `Stderr`. #[stable(feature = "rust1", since = "1.0.0")] pub struct StderrLock<'a> { - inner: MutexGuard<'a, StderrRaw>, + inner: ReentrantMutexGuard<'a, RefCell>, } /// Constructs a new reference to the standard error stream of a process. @@ -300,13 +304,13 @@ pub struct StderrLock<'a> { /// The returned handle implements the `Write` trait. #[stable(feature = "rust1", since = "1.0.0")] pub fn stderr() -> Stderr { - static INSTANCE: Lazy> = lazy_init!(stderr_init); + static INSTANCE: Lazy>> = lazy_init!(stderr_init); return Stderr { inner: INSTANCE.get().expect("cannot access stderr during shutdown"), }; - fn stderr_init() -> Arc> { - Arc::new(Mutex::new(stderr_raw())) + fn stderr_init() -> Arc>> { + Arc::new(ReentrantMutex::new(RefCell::new(stderr_raw()))) } } @@ -333,14 +337,18 @@ impl Write for Stderr { fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.lock().write_all(buf) } - // Don't override write_fmt for the same reasons as Stdout + fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> { + self.lock().write_fmt(args) + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Write for StderrLock<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(&buf[..cmp::min(buf.len(), OUT_MAX)]) + self.inner.borrow_mut().write(&buf[..cmp::min(buf.len(), OUT_MAX)]) + } + fn flush(&mut self) -> io::Result<()> { + self.inner.borrow_mut().flush() } - fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } /// Resets the task-local stderr handle to the specified writer diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index a7d8b287a64c0..654b33f1a579d 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -11,12 +11,12 @@ use prelude::v1::*; use sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; -use sync::poison::{self, LockResult}; -use sys::time::SteadyTime; +use sync::{mutex, MutexGuard, PoisonError}; use sys_common::condvar as sys; use sys_common::mutex as sys_mutex; +use sys_common::poison::{self, LockResult}; +use sys::time::SteadyTime; use time::Duration; -use sync::{mutex, MutexGuard, PoisonError}; /// A Condition Variable /// diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index a5259a00390f5..91e9714fbef48 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -20,15 +20,15 @@ pub use alloc::arc::{Arc, Weak}; pub use core::atomic; -pub use self::mutex::{Mutex, MutexGuard, StaticMutex}; -pub use self::mutex::MUTEX_INIT; -pub use self::rwlock::{RwLock, StaticRwLock, RW_LOCK_INIT}; -pub use self::rwlock::{RwLockReadGuard, RwLockWriteGuard}; +pub use self::barrier::{Barrier, BarrierWaitResult}; pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT}; +pub use self::mutex::MUTEX_INIT; +pub use self::mutex::{Mutex, MutexGuard, StaticMutex}; pub use self::once::{Once, ONCE_INIT}; +pub use sys_common::poison::{PoisonError, TryLockError, TryLockResult, LockResult}; +pub use self::rwlock::{RwLockReadGuard, RwLockWriteGuard}; +pub use self::rwlock::{RwLock, StaticRwLock, RW_LOCK_INIT}; pub use self::semaphore::{Semaphore, SemaphoreGuard}; -pub use self::barrier::{Barrier, BarrierWaitResult}; -pub use self::poison::{PoisonError, TryLockError, TryLockResult, LockResult}; pub use self::future::Future; @@ -39,6 +39,5 @@ mod condvar; mod future; mod mutex; mod once; -mod poison; mod rwlock; mod semaphore; diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 16e7f265412f3..46fb20cd6a2d6 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -11,11 +11,11 @@ use prelude::v1::*; use cell::UnsafeCell; +use fmt; use marker; use ops::{Deref, DerefMut}; -use sync::poison::{self, TryLockError, TryLockResult, LockResult}; use sys_common::mutex as sys; -use fmt; +use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// A mutual exclusion primitive useful for protecting shared data /// @@ -212,7 +212,7 @@ impl Mutex { /// Attempts to acquire this lock. /// - /// If the lock could not be acquired at this time, then `None` is returned. + /// If the lock could not be acquired at this time, then `Err` is returned. /// Otherwise, an RAII guard is returned. The lock will be unlocked when the /// guard is dropped. /// diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index d70350bc7d651..eb6d46a5dda7a 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -11,11 +11,11 @@ use prelude::v1::*; use cell::UnsafeCell; +use fmt; use marker; use ops::{Deref, DerefMut}; -use sync::poison::{self, LockResult, TryLockError, TryLockResult}; +use sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; use sys_common::rwlock as sys; -use fmt; /// A reader-writer lock /// diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index d2e2f1044d612..8a01eace889c3 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -29,6 +29,8 @@ pub mod condvar; pub mod mutex; pub mod net; pub mod net2; +pub mod poison; +pub mod remutex; pub mod rwlock; pub mod stack; pub mod thread; diff --git a/src/libstd/sync/poison.rs b/src/libstd/sys/common/poison.rs similarity index 100% rename from src/libstd/sync/poison.rs rename to src/libstd/sys/common/poison.rs diff --git a/src/libstd/sys/common/remutex.rs b/src/libstd/sys/common/remutex.rs new file mode 100644 index 0000000000000..b35063c0e2341 --- /dev/null +++ b/src/libstd/sys/common/remutex.rs @@ -0,0 +1,233 @@ +// 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. +#![unstable(feature = "reentrant_mutex", reason = "new API")] + +use prelude::v1::*; + +use fmt; +use marker; +use ops::Deref; +use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; +use sys::mutex as sys; + +/// A re-entrant mutual exclusion +/// +/// This mutex will block *other* threads waiting for the lock to become available. The thread +/// which has already locked the mutex can lock it multiple times without blocking, preventing a +/// common source of deadlocks. +pub struct ReentrantMutex { + inner: Box, + poison: poison::Flag, + data: T, +} + +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + + +/// An RAII implementation of a "scoped lock" of a mutex. When this structure is +/// dropped (falls out of scope), the lock will be unlocked. +/// +/// The data protected by the mutex can be accessed through this guard via its +/// Deref and DerefMut implementations +#[must_use] +pub struct ReentrantMutexGuard<'a, T: 'a> { + // funny underscores due to how Deref/DerefMut currently work (they + // disregard field privacy). + __lock: &'a ReentrantMutex, + __poison: poison::Guard, +} + +impl<'a, T> !marker::Send for ReentrantMutexGuard<'a, T> {} + + +impl ReentrantMutex { + /// Creates a new reentrant mutex in an unlocked state. + pub fn new(t: T) -> ReentrantMutex { + ReentrantMutex { + inner: box unsafe { sys::ReentrantMutex::new() }, + poison: poison::FLAG_INIT, + data: t, + } + } + + /// Acquires a mutex, blocking the current thread until it is able to do so. + /// + /// This function will block the caller until it is available to acquire the mutex. + /// Upon returning, the thread is the only thread with the mutex held. When the thread + /// calling this method already holds the lock, the call shall succeed without + /// blocking. + /// + /// # Failure + /// + /// If another user of this mutex panicked while holding the mutex, then + /// this call will return failure if the mutex would otherwise be + /// acquired. + pub fn lock(&self) -> LockResult> { + unsafe { self.inner.lock() } + ReentrantMutexGuard::new(&self) + } + + /// Attempts to acquire this lock. + /// + /// If the lock could not be acquired at this time, then `Err` is returned. + /// Otherwise, an RAII guard is returned. + /// + /// This function does not block. + /// + /// # Failure + /// + /// If another user of this mutex panicked while holding the mutex, then + /// this call will return failure if the mutex would otherwise be + /// acquired. + pub fn try_lock(&self) -> TryLockResult> { + if unsafe { self.inner.try_lock() } { + Ok(try!(ReentrantMutexGuard::new(&self))) + } else { + Err(TryLockError::WouldBlock) + } + } +} + +#[unsafe_destructor] +impl Drop for ReentrantMutex { + fn drop(&mut self) { + // This is actually safe b/c we know that there is no further usage of + // this mutex (it's up to the user to arrange for a mutex to get + // dropped, that's not our job) + unsafe { self.inner.destroy() } + } +} + +impl fmt::Debug for ReentrantMutex { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.try_lock() { + Ok(guard) => write!(f, "ReentrantMutex {{ data: {:?} }}", &*guard), + Err(TryLockError::Poisoned(err)) => { + write!(f, "ReentrantMutex {{ data: Poisoned({:?}) }}", &**err.get_ref()) + }, + Err(TryLockError::WouldBlock) => write!(f, "ReentrantMutex {{ }}") + } + } +} + +impl<'mutex, T> ReentrantMutexGuard<'mutex, T> { + fn new(lock: &'mutex ReentrantMutex) + -> LockResult> { + poison::map_result(lock.poison.borrow(), |guard| { + ReentrantMutexGuard { + __lock: lock, + __poison: guard, + } + }) + } +} + +impl<'mutex, T> Deref for ReentrantMutexGuard<'mutex, T> { + type Target = T; + + fn deref<'a>(&'a self) -> &'a T { + &self.__lock.data + } +} + +#[unsafe_destructor] +impl<'a, T> Drop for ReentrantMutexGuard<'a, T> { + #[inline] + fn drop(&mut self) { + unsafe { + self.__lock.poison.done(&self.__poison); + self.__lock.inner.unlock(); + } + } +} + + +#[cfg(test)] +mod test { + use prelude::v1::*; + use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; + use cell::RefCell; + use sync::Arc; + use boxed; + use thread; + + #[test] + fn smoke() { + let m = ReentrantMutex::new(()); + { + let a = m.lock().unwrap(); + { + let b = m.lock().unwrap(); + { + let c = m.lock().unwrap(); + assert_eq!(*c, ()); + } + assert_eq!(*b, ()); + } + assert_eq!(*a, ()); + } + } + + #[test] + fn is_mutex() { + let m = ReentrantMutex::new(RefCell::new(0)); + let lock = m.lock().unwrap(); + let handle = thread::scoped(|| { + let lock = m.lock().unwrap(); + assert_eq!(*lock.borrow(), 4950); + }); + for i in 0..100 { + let mut lock = m.lock().unwrap(); + *lock.borrow_mut() += i; + } + drop(lock); + drop(handle); + } + + #[test] + fn trylock_works() { + let m = ReentrantMutex::new(()); + let lock = m.try_lock().unwrap(); + let lock2 = m.try_lock().unwrap(); + { + thread::scoped(|| { + let lock = m.try_lock(); + assert!(lock.is_err()); + }); + } + let lock3 = m.try_lock().unwrap(); + } + + pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell>); + impl<'a> Drop for Answer<'a> { + fn drop(&mut self) { + *self.0.borrow_mut() = 42; + } + } + + #[test] + fn poison_works() { + let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); + let mc = m.clone(); + let result = thread::spawn(move ||{ + let lock = mc.lock().unwrap(); + *lock.borrow_mut() = 1; + let lock2 = mc.lock().unwrap(); + *lock.borrow_mut() = 2; + let answer = Answer(lock2); + panic!("What the answer to my lifetimes dilemma is?"); + drop(answer); + }).join(); + assert!(result.is_err()); + let r = m.lock().err().unwrap().into_inner(); + assert_eq!(*r.borrow(), 42); + } +} diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs index 1c0ce2938040d..af814653c1466 100644 --- a/src/libstd/sys/unix/mutex.rs +++ b/src/libstd/sys/unix/mutex.rs @@ -12,6 +12,7 @@ use prelude::v1::*; use cell::UnsafeCell; use sys::sync as ffi; +use mem; pub struct Mutex { inner: UnsafeCell } @@ -67,3 +68,50 @@ impl Mutex { debug_assert!(r == 0 || r == libc::EINVAL); } } + +// FIXME: remove the box, because box happens twice now, once at the common layer and once here. +// Box is necessary here, because mutex may not change address after it is intialised on some +// platforms. Regular Mutex above handles this by offloading intialisation to the OS on first lock. +// Sadly, as far as reentrant mutexes go, this scheme is not quite portable and we must initialise +// when we create the mutex, in the `new`. +pub struct ReentrantMutex { inner: Box> } + +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + +impl ReentrantMutex { + pub unsafe fn new() -> ReentrantMutex { + let mutex = ReentrantMutex { inner: box mem::uninitialized() }; + let mut attr: ffi::pthread_mutexattr_t = mem::uninitialized(); + let result = ffi::pthread_mutexattr_init(&mut attr as *mut _); + debug_assert_eq!(result, 0); + let result = ffi::pthread_mutexattr_settype(&mut attr as *mut _, + ffi::PTHREAD_MUTEX_RECURSIVE); + debug_assert_eq!(result, 0); + let result = ffi::pthread_mutex_init(mutex.inner.get(), &attr as *const _); + debug_assert_eq!(result, 0); + let result = ffi::pthread_mutexattr_destroy(&mut attr as *mut _); + debug_assert_eq!(result, 0); + mutex + } + + pub unsafe fn lock(&self) { + let result = ffi::pthread_mutex_lock(self.inner.get()); + debug_assert_eq!(result, 0); + } + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + ffi::pthread_mutex_trylock(self.inner.get()) == 0 + } + + pub unsafe fn unlock(&self) { + let result = ffi::pthread_mutex_unlock(self.inner.get()); + debug_assert_eq!(result, 0); + } + + pub unsafe fn destroy(&self) { + let result = ffi::pthread_mutex_destroy(self.inner.get()); + debug_assert_eq!(result, 0); + } +} diff --git a/src/libstd/sys/unix/sync.rs b/src/libstd/sys/unix/sync.rs index 3c05fd602be85..41e1e206a423a 100644 --- a/src/libstd/sys/unix/sync.rs +++ b/src/libstd/sys/unix/sync.rs @@ -12,17 +12,25 @@ use libc; -pub use self::os::{PTHREAD_MUTEX_INITIALIZER, pthread_mutex_t}; +pub use self::os::{PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_RECURSIVE, pthread_mutex_t, + pthread_mutexattr_t}; pub use self::os::{PTHREAD_COND_INITIALIZER, pthread_cond_t}; pub use self::os::{PTHREAD_RWLOCK_INITIALIZER, pthread_rwlock_t}; extern { // mutexes + pub fn pthread_mutex_init(lock: *mut pthread_mutex_t, attr: *const pthread_mutexattr_t) + -> libc::c_int; pub fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int; pub fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int; pub fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int; pub fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int; + pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> libc::c_int; + pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> libc::c_int; + pub fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, _type: libc::c_int) + -> libc::c_int; + // cvars pub fn pthread_cond_wait(cond: *mut pthread_cond_t, lock: *mut pthread_mutex_t) -> libc::c_int; @@ -52,12 +60,14 @@ mod os { use libc; pub type pthread_mutex_t = *mut libc::c_void; + pub type pthread_mutexattr_t = *mut libc::c_void; pub type pthread_cond_t = *mut libc::c_void; pub type pthread_rwlock_t = *mut libc::c_void; pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = 0 as *mut _; pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = 0 as *mut _; pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = 0 as *mut _; + pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2; } #[cfg(any(target_os = "macos", target_os = "ios"))] @@ -95,6 +105,12 @@ mod os { __opaque: [u8; __PTHREAD_MUTEX_SIZE__], } #[repr(C)] + pub struct pthread_mutexattr_t { + __sig: libc::c_long, + // note, that this is 16 bytes just to be safe, the actual struct might be smaller. + __opaque: [u8; 16], + } + #[repr(C)] pub struct pthread_cond_t { __sig: libc::c_long, __opaque: [u8; __PTHREAD_COND_SIZE__], @@ -117,6 +133,8 @@ mod os { __sig: _PTHREAD_RWLOCK_SIG_INIT, __opaque: [0; __PTHREAD_RWLOCK_SIZE__], }; + + pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2; } #[cfg(target_os = "linux")] @@ -161,6 +179,12 @@ mod os { size: [u8; __SIZEOF_PTHREAD_MUTEX_T], } #[repr(C)] + pub struct pthread_mutexattr_t { + __align: libc::c_longlong, + // note, that this is 16 bytes just to be safe, the actual struct might be smaller. + size: [u8; 16], + } + #[repr(C)] pub struct pthread_cond_t { __align: libc::c_longlong, size: [u8; __SIZEOF_PTHREAD_COND_T], @@ -183,6 +207,7 @@ mod os { __align: 0, size: [0; __SIZEOF_PTHREAD_RWLOCK_T], }; + pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1; } #[cfg(target_os = "android")] mod os { @@ -190,6 +215,7 @@ mod os { #[repr(C)] pub struct pthread_mutex_t { value: libc::c_int } + pub type pthread_mutexattr_t = libc::c_long; #[repr(C)] pub struct pthread_cond_t { value: libc::c_int } #[repr(C)] @@ -218,4 +244,5 @@ mod os { pendingWriters: 0, reserved: [0 as *mut _; 4], }; + pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1; } diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index 0847f3b52bfab..ca20858bb5bc5 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -12,6 +12,7 @@ use prelude::v1::*; use cell::UnsafeCell; use sys::sync as ffi; +use mem; pub struct Mutex { inner: UnsafeCell } @@ -57,3 +58,33 @@ impl Mutex { // ... } } + +pub struct ReentrantMutex { inner: Box> } + +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + +impl ReentrantMutex { + pub unsafe fn new() -> ReentrantMutex { + let mutex = ReentrantMutex { inner: box mem::uninitialized() }; + ffi::InitializeCriticalSection(mutex.inner.get()); + mutex + } + + pub unsafe fn lock(&self) { + ffi::EnterCriticalSection(self.inner.get()); + } + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + ffi::TryEnterCriticalSection(self.inner.get()) != 0 + } + + pub unsafe fn unlock(&self) { + ffi::LeaveCriticalSection(self.inner.get()); + } + + pub unsafe fn destroy(&self) { + ffi::DeleteCriticalSection(self.inner.get()); + } +} diff --git a/src/libstd/sys/windows/sync.rs b/src/libstd/sys/windows/sync.rs index 7614104c98bf3..5410259540eac 100644 --- a/src/libstd/sys/windows/sync.rs +++ b/src/libstd/sys/windows/sync.rs @@ -8,17 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use libc::{BOOL, DWORD, LPVOID, c_ulong}; +use libc::{BOOL, DWORD, LPVOID, LONG, HANDLE, c_ulong}; use libc::types::os::arch::extra::BOOLEAN; pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; pub type PSRWLOCK = *mut SRWLOCK; pub type ULONG = c_ulong; +pub type ULONG_PTR = c_ulong; #[repr(C)] pub struct CONDITION_VARIABLE { pub ptr: LPVOID } #[repr(C)] pub struct SRWLOCK { pub ptr: LPVOID } +#[repr(C)] +pub struct CRITICAL_SECTION { + CriticalSectionDebug: LPVOID, + LockCount: LONG, + RecursionCount: LONG, + OwningThread: HANDLE, + LockSemaphore: HANDLE, + SpinCount: ULONG_PTR +} pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { ptr: 0 as *mut _, @@ -41,4 +51,10 @@ extern "system" { pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK); pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN; pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN; + + pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION); + pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION); + pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOLEAN; + pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION); + pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION); } diff --git a/src/test/run-pass/atomic-print.rs b/src/test/run-pass/atomic-print.rs new file mode 100644 index 0000000000000..df3b572bce49b --- /dev/null +++ b/src/test/run-pass/atomic-print.rs @@ -0,0 +1,48 @@ +// 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::{env, fmt, process, sync, thread}; + +struct SlowFmt(u32); +impl fmt::Debug for SlowFmt { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + thread::sleep_ms(3); + self.0.fmt(f) + } +} + +fn do_print(x: u32) { + let x = SlowFmt(x); + println!("{:?}{:?}{:?}{:?}{:?}", x, x, x, x, x); +} + +fn main(){ + if env::args().count() == 2 { + let barrier = sync::Arc::new(sync::Barrier::new(2)); + let tbarrier = barrier.clone(); + let t = thread::scoped(||{ + tbarrier.wait(); + do_print(1); + }); + barrier.wait(); + do_print(2); + t.join(); + } else { + let this = env::args().next().unwrap(); + let output = process::Command::new(this).arg("-").output().unwrap(); + for line in String::from_utf8(output.stdout).unwrap().lines() { + match line.chars().next().unwrap() { + '1' => assert_eq!(line, "11111"), + '2' => assert_eq!(line, "22222"), + _ => panic!("Unexpected character") + } + } + } +} From 45eb54c870df94805d8e71525fd30844137905cf Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 8 Apr 2015 12:06:29 -0700 Subject: [PATCH 29/62] configure: Remove obsolete --nightly flag --- configure | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/configure b/configure index ef474fcf79dab..8c190a6f42b22 100755 --- a/configure +++ b/configure @@ -1,4 +1,4 @@ -#!/bin/sh +<#!/bin/sh msg() { echo "configure: $1" @@ -540,7 +540,6 @@ opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds" opt local-rust 0 "use an installed rustc rather than downloading a snapshot" opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM" opt rpath 0 "build rpaths into rustc itself" -opt nightly 0 "build nightly packages" opt verify-install 1 "verify installed binaries work" # This is used by the automation to produce single-target nightlies opt dist-host-only 0 "only install bins for the host architecture" @@ -556,6 +555,7 @@ valopt llvm-root "" "set LLVM root" valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located" valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple" valopt android-cross-path "/opt/ndk_standalone" "Android NDK standalone path" +valopt release-channel "dev" "the name of the release channel to build" # Many of these are saved below during the "writing configuration" step # (others are conditionally saved). @@ -568,7 +568,6 @@ valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary" valopt_nosave host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples" valopt_nosave target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples" valopt_nosave mandir "${CFG_PREFIX}/share/man" "install man pages in PATH" -valopt_nosave release-channel "dev" "the name of the release channel to build" # Temporarily support old triples until buildbots get updated CFG_BUILD=$(to_llvm_triple $CFG_BUILD) @@ -621,14 +620,6 @@ case "$CFG_RELEASE_CHANNEL" in ;; esac -# Continue supporting the old --enable-nightly flag to transition the bots -# XXX Remove me -if [ ! -z "$CFG_ENABLE_NIGHTLY" ] -then - CFG_RELEASE_CHANNEL=nightly -fi -putvar CFG_RELEASE_CHANNEL - # A magic value that allows the compiler to use unstable features # during the bootstrap even when doing so would normally be an error # because of feature staging or because the build turns on From bc9f16c59960cfb306178428956f8446337d27e7 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 8 Apr 2015 12:16:45 -0700 Subject: [PATCH 30/62] configure: Remove obsolete --disable-verify option rust-installer never verifies. --- configure | 1 - mk/install.mk | 10 ++-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/configure b/configure index 8c190a6f42b22..51e9ad7d88e5f 100755 --- a/configure +++ b/configure @@ -540,7 +540,6 @@ opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds" opt local-rust 0 "use an installed rustc rather than downloading a snapshot" opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM" opt rpath 0 "build rpaths into rustc itself" -opt verify-install 1 "verify installed binaries work" # This is used by the automation to produce single-target nightlies opt dist-host-only 0 "only install bins for the host architecture" opt inject-std-version 1 "inject the current compiler version of libstd into programs" diff --git a/mk/install.mk b/mk/install.mk index 8850cd778035f..cabc97a1e4912 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -8,12 +8,6 @@ # option. This file may not be copied, modified, or distributed # except according to those terms. -ifdef CFG_DISABLE_VERIFY_INSTALL -MAYBE_DISABLE_VERIFY=--disable-verify -else -MAYBE_DISABLE_VERIFY= -endif - install: ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER))) # Build the dist as the original user @@ -22,9 +16,9 @@ else $(Q)$(MAKE) prepare_install endif ifeq ($(CFG_DISABLE_DOCS),) - $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" "$(MAYBE_DISABLE_VERIFY)" + $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" endif - $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" "$(MAYBE_DISABLE_VERIFY)" + $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" # Remove tmp files because it's a decent amount of disk space $(Q)rm -R tmp/dist From ed8eebd99b65c54d95ce4302ddff1633ed96549b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 8 Apr 2015 13:17:46 -0700 Subject: [PATCH 31/62] configure: Rename --enable-debug to --enable-debug-assertions --- configure | 4 ++-- mk/main.mk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure b/configure index 51e9ad7d88e5f..6564c8c26e431 100755 --- a/configure +++ b/configure @@ -1,4 +1,4 @@ -<#!/bin/sh +#!/bin/sh msg() { echo "configure: $1" @@ -534,7 +534,7 @@ opt optimize-llvm 1 "build optimized LLVM" opt optimize-tests 1 "build tests with optimizations" opt libcpp 1 "build with llvm with libc++ instead of libstdc++ when using clang" opt llvm-assertions 1 "build LLVM with assertions" -opt debug 1 "build with extra debug fun" +opt debug-assertions 1 "build with extra debug fun" opt fast-make 0 "use .gitmodules as timestamp for submodule deps" opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds" opt local-rust 0 "use an installed rustc rather than downloading a snapshot" diff --git a/mk/main.mk b/mk/main.mk index b9f2cf1cce89c..4428dcc43c877 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -126,10 +126,10 @@ endif CFG_JEMALLOC_FLAGS += $(JEMALLOC_FLAGS) -ifdef CFG_DISABLE_DEBUG +ifdef CFG_DISABLE_DEBUG_ASSERTIONS CFG_RUSTC_FLAGS += --cfg ndebug else - $(info cfg: enabling more debugging (CFG_ENABLE_DEBUG)) + $(info cfg: enabling more debugging (CFG_ENABLE_DEBUG_ASSERTIONS)) CFG_RUSTC_FLAGS += --cfg debug -C debug-assertions=on endif From 59e332bd2f3cd448b3976b919caeebede15a9694 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 8 Apr 2015 13:23:44 -0700 Subject: [PATCH 32/62] configure: Disable debug assertions by default --- configure | 2 +- mk/main.mk | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure b/configure index 6564c8c26e431..b301ad73c81bc 100755 --- a/configure +++ b/configure @@ -534,7 +534,7 @@ opt optimize-llvm 1 "build optimized LLVM" opt optimize-tests 1 "build tests with optimizations" opt libcpp 1 "build with llvm with libc++ instead of libstdc++ when using clang" opt llvm-assertions 1 "build LLVM with assertions" -opt debug-assertions 1 "build with extra debug fun" +opt debug-assertions 0 "build with extra debug fun" opt fast-make 0 "use .gitmodules as timestamp for submodule deps" opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds" opt local-rust 0 "use an installed rustc rather than downloading a snapshot" diff --git a/mk/main.mk b/mk/main.mk index 4428dcc43c877..0c80c3f84f0dc 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -126,11 +126,11 @@ endif CFG_JEMALLOC_FLAGS += $(JEMALLOC_FLAGS) -ifdef CFG_DISABLE_DEBUG_ASSERTIONS - CFG_RUSTC_FLAGS += --cfg ndebug -else +ifdef CFG_ENABLE_DEBUG_ASSERTIONS $(info cfg: enabling more debugging (CFG_ENABLE_DEBUG_ASSERTIONS)) CFG_RUSTC_FLAGS += --cfg debug -C debug-assertions=on +else + CFG_RUSTC_FLAGS += --cfg ndebug endif ifdef SAVE_TEMPS From 2cdfd372e2565a35374977da5c20ce6069c4aa41 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 8 Apr 2015 13:25:20 -0700 Subject: [PATCH 33/62] configure: Clarify help message for --enable-debug-assertions --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index b301ad73c81bc..9ff1765775eec 100755 --- a/configure +++ b/configure @@ -534,7 +534,7 @@ opt optimize-llvm 1 "build optimized LLVM" opt optimize-tests 1 "build tests with optimizations" opt libcpp 1 "build with llvm with libc++ instead of libstdc++ when using clang" opt llvm-assertions 1 "build LLVM with assertions" -opt debug-assertions 0 "build with extra debug fun" +opt debug-assertions 0 "build with debugging assertions" opt fast-make 0 "use .gitmodules as timestamp for submodule deps" opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds" opt local-rust 0 "use an installed rustc rather than downloading a snapshot" From 8545d2ce5358b7b04d8be4531cf8b0ffb9a2e794 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 8 Apr 2015 13:27:12 -0700 Subject: [PATCH 34/62] configure: Disable LLVM asserts by default --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 9ff1765775eec..8620e1425d034 100755 --- a/configure +++ b/configure @@ -533,7 +533,7 @@ opt optimize-cxx 1 "build optimized C++ code" opt optimize-llvm 1 "build optimized LLVM" opt optimize-tests 1 "build tests with optimizations" opt libcpp 1 "build with llvm with libc++ instead of libstdc++ when using clang" -opt llvm-assertions 1 "build LLVM with assertions" +opt llvm-assertions 0 "build LLVM with assertions" opt debug-assertions 0 "build with debugging assertions" opt fast-make 0 "use .gitmodules as timestamp for submodule deps" opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds" @@ -1170,7 +1170,7 @@ do LLVM_DBG_OPTS="--enable-optimized" LLVM_INST_DIR=$LLVM_BUILD_DIR/Release fi - if [ ! -z "$CFG_DISABLE_LLVM_ASSERTIONS" ] + if [ -z "$CFG_ENABLE_LLVM_ASSERTIONS" ] then LLVM_ASSERTION_OPTS="--disable-assertions" else From 1b34f0aef0a843f4e5aa8b2d457162f9d58f52d8 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 8 Apr 2015 13:31:26 -0700 Subject: [PATCH 35/62] configure: Clarify --enable-debug-assertions status message --- mk/main.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mk/main.mk b/mk/main.mk index 0c80c3f84f0dc..98b9dda1251c7 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -127,7 +127,7 @@ endif CFG_JEMALLOC_FLAGS += $(JEMALLOC_FLAGS) ifdef CFG_ENABLE_DEBUG_ASSERTIONS - $(info cfg: enabling more debugging (CFG_ENABLE_DEBUG_ASSERTIONS)) + $(info cfg: enabling debug assertions (CFG_ENABLE_DEBUG_ASSERTIONS)) CFG_RUSTC_FLAGS += --cfg debug -C debug-assertions=on else CFG_RUSTC_FLAGS += --cfg ndebug From 7cbf8233539d74b9c6a3b1bdc67c66bfb9e0ce7e Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 8 Apr 2015 13:57:37 -0700 Subject: [PATCH 36/62] configure: Add --enable-debuginfo --- configure | 1 + mk/main.mk | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/configure b/configure index 8620e1425d034..3fe9d543c5d38 100755 --- a/configure +++ b/configure @@ -535,6 +535,7 @@ opt optimize-tests 1 "build tests with optimizations" opt libcpp 1 "build with llvm with libc++ instead of libstdc++ when using clang" opt llvm-assertions 0 "build LLVM with assertions" opt debug-assertions 0 "build with debugging assertions" +opt debuginfo 0 "build with debugger metadata" opt fast-make 0 "use .gitmodules as timestamp for submodule deps" opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds" opt local-rust 0 "use an installed rustc rather than downloading a snapshot" diff --git a/mk/main.mk b/mk/main.mk index 98b9dda1251c7..ea00444453d00 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -133,6 +133,11 @@ else CFG_RUSTC_FLAGS += --cfg ndebug endif +ifdef CFG_ENABLE_DEBUGINFO + $(info cfg: enabling debuginfo (CFG_ENABLE_DEBUGINFO)) + CFG_RUSTC_FLAGS += -g +endif + ifdef SAVE_TEMPS CFG_RUSTC_FLAGS += --save-temps endif From 0cb937944664f7a52895c87f9007fcdface78a7e Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Wed, 8 Apr 2015 12:52:58 -0700 Subject: [PATCH 37/62] Allow plugins to register LLVM passes --- src/librustc/plugin/registry.rs | 14 ++++++++++ src/librustc/session/mod.rs | 2 ++ src/librustc_driver/driver.rs | 4 ++- src/librustc_trans/back/write.rs | 15 ++++++++++ src/test/auxiliary/llvm_pass_plugin.rs | 28 +++++++++++++++++++ .../run-pass-fulldeps/llvm-pass-plugin.rs | 17 +++++++++++ 6 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src/test/auxiliary/llvm_pass_plugin.rs create mode 100644 src/test/run-pass-fulldeps/llvm-pass-plugin.rs diff --git a/src/librustc/plugin/registry.rs b/src/librustc/plugin/registry.rs index a73ed04ac0a41..322b5d3a8cf27 100644 --- a/src/librustc/plugin/registry.rs +++ b/src/librustc/plugin/registry.rs @@ -22,6 +22,7 @@ use syntax::ptr::P; use syntax::ast; use std::collections::HashMap; +use std::borrow::ToOwned; /// Structure used to register plugins. /// @@ -50,6 +51,9 @@ pub struct Registry<'a> { #[doc(hidden)] pub lint_groups: HashMap<&'static str, Vec>, + + #[doc(hidden)] + pub llvm_passes: Vec, } impl<'a> Registry<'a> { @@ -62,6 +66,7 @@ impl<'a> Registry<'a> { syntax_exts: vec!(), lint_passes: vec!(), lint_groups: HashMap::new(), + llvm_passes: vec!(), } } @@ -116,4 +121,13 @@ impl<'a> Registry<'a> { pub fn register_lint_group(&mut self, name: &'static str, to: Vec<&'static Lint>) { self.lint_groups.insert(name, to.into_iter().map(|x| LintId::of(x)).collect()); } + + /// Register an LLVM pass. + /// + /// Registration with LLVM itself is handled through static C++ objects with + /// constructors. This method simply adds a name to the list of passes to + /// execute. + pub fn register_llvm_pass(&mut self, name: &str) { + self.llvm_passes.push(name.to_owned()); + } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 452840310aa41..148f484b0ed5c 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -52,6 +52,7 @@ pub struct Session { pub working_dir: PathBuf, pub lint_store: RefCell, pub lints: RefCell>>, + pub plugin_llvm_passes: RefCell>, pub crate_types: RefCell>, pub crate_metadata: RefCell>, pub features: RefCell, @@ -391,6 +392,7 @@ pub fn build_session_(sopts: config::Options, working_dir: env::current_dir().unwrap(), lint_store: RefCell::new(lint::LintStore::new()), lints: RefCell::new(NodeMap()), + plugin_llvm_passes: RefCell::new(Vec::new()), crate_types: RefCell::new(Vec::new()), crate_metadata: RefCell::new(Vec::new()), features: RefCell::new(feature_gate::Features::new()), diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index fe05b489229ad..e310798b20ab7 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -438,7 +438,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, } }); - let Registry { syntax_exts, lint_passes, lint_groups, .. } = registry; + let Registry { syntax_exts, lint_passes, lint_groups, llvm_passes, .. } = registry; { let mut ls = sess.lint_store.borrow_mut(); @@ -449,6 +449,8 @@ pub fn phase_2_configure_and_expand(sess: &Session, for (name, to) in lint_groups { ls.register_group(Some(sess), true, name, to); } + + *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; } // Lint plugins are registered; now we can process command line flags. diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index cc588a365f6e6..de21d62651499 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -319,6 +319,8 @@ struct CodegenContext<'a> { lto_ctxt: Option<(&'a Session, &'a [String])>, // Handler to use for diagnostics produced during codegen. handler: &'a Handler, + // LLVM passes added by plugins. + plugin_passes: Vec, // LLVM optimizations for which we want to print remarks. remark: Passes, } @@ -328,6 +330,7 @@ impl<'a> CodegenContext<'a> { CodegenContext { lto_ctxt: Some((sess, reachable)), handler: sess.diagnostic().handler(), + plugin_passes: sess.plugin_llvm_passes.borrow().clone(), remark: sess.opts.cg.remark.clone(), } } @@ -461,6 +464,16 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } } + for pass in &cgcx.plugin_passes { + let pass = CString::new(pass.clone()).unwrap(); + if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) { + cgcx.handler.err(&format!("a plugin asked for LLVM pass {:?} but LLVM \ + does not recognize it", pass)); + } + } + + cgcx.handler.abort_if_errors(); + // Finally, run the actual optimization passes time(config.time_passes, "llvm function passes", (), |()| llvm::LLVMRustRunFunctionPassManager(fpm, llmod)); @@ -907,6 +920,7 @@ fn run_work_multithreaded(sess: &Session, for i in 0..num_workers { let work_items_arc = work_items_arc.clone(); let diag_emitter = diag_emitter.clone(); + let plugin_passes = sess.plugin_llvm_passes.borrow().clone(); let remark = sess.opts.cg.remark.clone(); let (tx, rx) = channel(); @@ -921,6 +935,7 @@ fn run_work_multithreaded(sess: &Session, let cgcx = CodegenContext { lto_ctxt: None, handler: &diag_handler, + plugin_passes: plugin_passes, remark: remark, }; diff --git a/src/test/auxiliary/llvm_pass_plugin.rs b/src/test/auxiliary/llvm_pass_plugin.rs new file mode 100644 index 0000000000000..d61f47fd7ef27 --- /dev/null +++ b/src/test/auxiliary/llvm_pass_plugin.rs @@ -0,0 +1,28 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host + +#![feature(plugin_registrar)] +#![feature(rustc_private)] + +extern crate rustc; + +use rustc::plugin::Registry; + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + // This pass is built in to LLVM. + // + // Normally, we would name a pass that was registered through + // C++ static object constructors in the same .so file as the + // plugin registrar. + reg.register_llvm_pass("inline"); +} diff --git a/src/test/run-pass-fulldeps/llvm-pass-plugin.rs b/src/test/run-pass-fulldeps/llvm-pass-plugin.rs new file mode 100644 index 0000000000000..5dfef636f9f36 --- /dev/null +++ b/src/test/run-pass-fulldeps/llvm-pass-plugin.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. + +// aux-build:llvm_pass_plugin.rs +// ignore-stage1 + +#![feature(plugin)] +#![plugin(llvm_pass_plugin)] + +pub fn main() { } From 1002155c755562b8932251b50dac149edf8c885b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 8 Apr 2015 14:21:36 -0700 Subject: [PATCH 38/62] Add --enable-debug to control multiple perf options --- configure | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 3fe9d543c5d38..4d2868ede5c95 100755 --- a/configure +++ b/configure @@ -523,19 +523,16 @@ fi BOOL_OPTIONS="" VAL_OPTIONS="" +opt debug 0 "debug mode" opt valgrind 0 "run tests with valgrind (memcheck by default)" opt helgrind 0 "run tests with helgrind instead of memcheck" opt valgrind-rpass 1 "run rpass-valgrind tests with valgrind" opt docs 1 "build standard library documentation" opt compiler-docs 0 "build compiler documentation" -opt optimize 1 "build optimized rust code" -opt optimize-cxx 1 "build optimized C++ code" -opt optimize-llvm 1 "build optimized LLVM" opt optimize-tests 1 "build tests with optimizations" opt libcpp 1 "build with llvm with libc++ instead of libstdc++ when using clang" opt llvm-assertions 0 "build LLVM with assertions" opt debug-assertions 0 "build with debugging assertions" -opt debuginfo 0 "build with debugger metadata" opt fast-make 0 "use .gitmodules as timestamp for submodule deps" opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds" opt local-rust 0 "use an installed rustc rather than downloading a snapshot" @@ -546,6 +543,14 @@ opt dist-host-only 0 "only install bins for the host architecture" opt inject-std-version 1 "inject the current compiler version of libstd into programs" opt llvm-version-check 1 "don't check if the LLVM version is supported, build anyway" +# Optimization and debugging options. These may be overridden by the release channel, etc. +opt_nosave optimize 1 "build optimized rust code" +opt_nosave optimize-cxx 1 "build optimized C++ code" +opt_nosave optimize-llvm 1 "build optimized LLVM" +opt_nosave llvm-assertions 0 "build LLVM with assertions" +opt_nosave debug-assertions 0 "build with debugging assertions" +opt_nosave debuginfo 0 "build with debugger metadata" + valopt localstatedir "/var/lib" "local state directory" valopt sysconfdir "/etc" "install system configuration files" @@ -620,6 +625,24 @@ case "$CFG_RELEASE_CHANNEL" in ;; esac +# Adjust perf and debug options for debug mode +if [ -n "$CFG_ENABLE_DEBUG" ]; then + msg "debug mode enabled, setting performance options" + CFG_DISABLE_OPTIMIZE=1 + CFG_DISABLE_OPTIMIZE_CXX=1 + CFG_DISABLE_OPTIMIZE_LLVM=1 + CFG_ENABLE_LLVM_ASSERTIONS=1 + CFG_ENABLE_DEBUG_ASSERTIONS=1 +fi + +# OK, now write the debugging options +if [ -n "$CFG_DISABLE_OPTIMIZE" ]; then putvar CFG_DISABLE_OPTIMIZE; fi +if [ -n "$CFG_DISABLE_OPTIMIZE_CXX" ]; then putvar CFG_DISABLE_OPTIMIZE_CXX; fi +if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then putvar CFG_DISABLE_OPTIMIZE_LLVM; fi +if [ -n "$CFG_ENABLE_LLVM_ASSERTIONS" ]; then putvar CFG_ENABLE_LLVM_ASSERTIONS; fi +if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTIONS; fi +if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi + # A magic value that allows the compiler to use unstable features # during the bootstrap even when doing so would normally be an error # because of feature staging or because the build turns on @@ -1425,6 +1448,11 @@ move_if_changed config.tmp config.mk rm -f config.tmp touch config.stamp -step_msg "complete" +if [ -z "$CFG_ENABLE_DEBUG" ]; then + step_msg "configured in release mode. for development consider --enable-debug" +else + step_msg "complete" +fi + msg "run \`make help\`" msg From 6d17c35cd5fb806eb81441a1cbea755b0efc41ad Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 8 Apr 2015 15:12:08 -0700 Subject: [PATCH 39/62] configure: Add --enable-debug-jemalloc --- configure | 3 +++ mk/rt.mk | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/configure b/configure index 4d2868ede5c95..b23cfaf976f0e 100755 --- a/configure +++ b/configure @@ -550,6 +550,7 @@ opt_nosave optimize-llvm 1 "build optimized LLVM" opt_nosave llvm-assertions 0 "build LLVM with assertions" opt_nosave debug-assertions 0 "build with debugging assertions" opt_nosave debuginfo 0 "build with debugger metadata" +opt_nosave debug-jemalloc 0 "build jemalloc with --enable-debug --enable-fill" valopt localstatedir "/var/lib" "local state directory" valopt sysconfdir "/etc" "install system configuration files" @@ -633,6 +634,7 @@ if [ -n "$CFG_ENABLE_DEBUG" ]; then CFG_DISABLE_OPTIMIZE_LLVM=1 CFG_ENABLE_LLVM_ASSERTIONS=1 CFG_ENABLE_DEBUG_ASSERTIONS=1 + CFG_ENABLE_DEBUG_JEMALLOC=1 fi # OK, now write the debugging options @@ -642,6 +644,7 @@ if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then putvar CFG_DISABLE_OPTIMIZE_LLVM; f if [ -n "$CFG_ENABLE_LLVM_ASSERTIONS" ]; then putvar CFG_ENABLE_LLVM_ASSERTIONS; fi if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTIONS; fi if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi +if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi # A magic value that allows the compiler to use unstable features # during the bootstrap even when doing so would normally be an error diff --git a/mk/rt.mk b/mk/rt.mk index 527485c502936..70abce8b46067 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -143,6 +143,10 @@ else ifeq ($(findstring android, $(OSTYPE_$(1))), android) JEMALLOC_ARGS_$(1) := --disable-tls endif +ifdef CFG_ENABLE_DEBUG_JEMALLOC + JEMALLOC_ARGS_$(1) += --enable-debug --enable-fill +endif + ################################################################################ # jemalloc ################################################################################ From 2a9e1011b1af99b00557f122b2bf4a645b274b90 Mon Sep 17 00:00:00 2001 From: Luke Gallagher Date: Thu, 9 Apr 2015 08:20:51 +1000 Subject: [PATCH 40/62] Remove `ignore-tidy-linelength` from tests that no longer need it --- src/test/compile-fail/bad-mid-path-type-params.rs | 2 -- src/test/compile-fail/bad-sized.rs | 2 -- src/test/compile-fail/coherence-default-trait-impl.rs | 2 -- src/test/compile-fail/coherence-orphan.rs | 1 - src/test/compile-fail/issue-8767.rs | 2 -- src/test/compile-fail/lint-stability.rs | 1 - src/test/compile-fail/lint-uppercase-variables.rs | 2 -- .../compile-fail/typeck-default-trait-impl-outside-crate.rs | 2 -- .../compile-fail/use-after-move-implicity-coerced-object.rs | 2 -- src/test/debuginfo/gdb-pretty-std.rs | 1 - 10 files changed, 17 deletions(-) diff --git a/src/test/compile-fail/bad-mid-path-type-params.rs b/src/test/compile-fail/bad-mid-path-type-params.rs index 7a7406115d393..20ac757354faf 100644 --- a/src/test/compile-fail/bad-mid-path-type-params.rs +++ b/src/test/compile-fail/bad-mid-path-type-params.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - struct S { contents: T, } diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index 1944acbe1f345..5878e9a9f649b 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - use std::cell::RefCell; trait Trait : ::std::marker::MarkerTrait {} diff --git a/src/test/compile-fail/coherence-default-trait-impl.rs b/src/test/compile-fail/coherence-default-trait-impl.rs index a5b317307379e..062a4a43b694b 100644 --- a/src/test/compile-fail/coherence-default-trait-impl.rs +++ b/src/test/compile-fail/coherence-default-trait-impl.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - #![feature(optin_builtin_traits)] use std::marker::MarkerTrait; diff --git a/src/test/compile-fail/coherence-orphan.rs b/src/test/compile-fail/coherence-orphan.rs index 2243a0507f2d1..78435f1a78a16 100644 --- a/src/test/compile-fail/coherence-orphan.rs +++ b/src/test/compile-fail/coherence-orphan.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength // aux-build:coherence_orphan_lib.rs #![feature(optin_builtin_traits)] diff --git a/src/test/compile-fail/issue-8767.rs b/src/test/compile-fail/issue-8767.rs index 9abd8c9e3fcda..96c8ec4505856 100644 --- a/src/test/compile-fail/issue-8767.rs +++ b/src/test/compile-fail/issue-8767.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - impl B { //~ ERROR use of undeclared type name `B` } diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index 391b49e10686e..16f195b4ea268 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -12,7 +12,6 @@ // aux-build:inherited_stability.rs // aux-build:stability_cfg1.rs // aux-build:stability_cfg2.rs -// ignore-tidy-linelength #![deny(deprecated)] #![allow(dead_code)] diff --git a/src/test/compile-fail/lint-uppercase-variables.rs b/src/test/compile-fail/lint-uppercase-variables.rs index 517be0eb8acd9..1615af400713c 100644 --- a/src/test/compile-fail/lint-uppercase-variables.rs +++ b/src/test/compile-fail/lint-uppercase-variables.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - #![allow(dead_code)] #![deny(non_snake_case)] diff --git a/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs b/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs index a345bd1b65c0e..09b97dfb30f24 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - #![feature(optin_builtin_traits)] impl Copy for .. {} diff --git a/src/test/compile-fail/use-after-move-implicity-coerced-object.rs b/src/test/compile-fail/use-after-move-implicity-coerced-object.rs index 26d22b072eb48..addc572175231 100644 --- a/src/test/compile-fail/use-after-move-implicity-coerced-object.rs +++ b/src/test/compile-fail/use-after-move-implicity-coerced-object.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - #![feature(box_syntax)] use std::fmt; diff --git a/src/test/debuginfo/gdb-pretty-std.rs b/src/test/debuginfo/gdb-pretty-std.rs index dbf80a9bccce8..1da9a06b0eea4 100644 --- a/src/test/debuginfo/gdb-pretty-std.rs +++ b/src/test/debuginfo/gdb-pretty-std.rs @@ -10,7 +10,6 @@ // ignore-windows failing on win32 bot // ignore-freebsd: gdb package too new -// ignore-tidy-linelength // ignore-lldb // ignore-android: FIXME(#10381) // compile-flags:-g From 65e3f0325a64d8f1affa146b3575a4b7c90458d7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 8 Apr 2015 15:48:46 -0700 Subject: [PATCH 41/62] std: Destabilize the internals of panic! Now that we have a `#[allow_internal_unstable]` attribute for macros there's no need for these two `begin_unwind` functions to be stable. Right now the `panic!` interface is the only one we wish to stabilize, so remove the stability markers from these functions. While this is a breaking change, it is highly unlikely to break any actual code. It is recommended to use the `panic!` macro instead if it breaks explicit calls into `std::rt`. [breaking-change] cc #24208 --- src/libstd/macros.rs | 1 + src/libstd/rt/unwind.rs | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index b3d1adb44218a..3d10c151f80d6 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -37,6 +37,7 @@ /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[allow_internal_unstable] macro_rules! panic { () => ({ panic!("explicit panic") diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index f71811b1eadf6..2f58a437eb472 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -495,7 +495,6 @@ pub extern fn rust_begin_unwind(msg: fmt::Arguments, /// on (e.g.) the inlining of other functions as possible), by moving /// the actual formatting into this shared place. #[inline(never)] #[cold] -#[stable(since = "1.0.0", feature = "rust1")] pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, usize)) -> ! { use fmt::Write; @@ -511,7 +510,6 @@ pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, usize)) /// This is the entry point of unwinding for panic!() and assert!(). #[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible -#[stable(since = "1.0.0", feature = "rust1")] pub fn begin_unwind(msg: M, file_line: &(&'static str, usize)) -> ! { // Note that this should be the only allocation performed in this code path. // Currently this means that panic!() on OOM will invoke this code path, @@ -598,7 +596,6 @@ fn begin_unwind_inner(msg: Box, /// Only a limited number of callbacks can be registered, and this function /// returns whether the callback was successfully registered or not. It is not /// currently possible to unregister a callback once it has been registered. -#[unstable(feature = "std_misc")] pub unsafe fn register(f: Callback) -> bool { match CALLBACK_CNT.fetch_add(1, Ordering::SeqCst) { // The invocation code has knowledge of this window where the count has From 6b32072c0c958949a4b6946bb7adb29241804454 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 8 Apr 2015 16:38:38 -0700 Subject: [PATCH 42/62] std: Stabilize Clone::clone_from This method hasn't really changed since is inception, and it can often be a nice performance win for some situations. This method also imposes no burden on implementors or users of `Clone` as it's just a default method on the side. --- src/libcore/clone.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 85e5bde48598e..0ded6a4b364b1 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -44,8 +44,7 @@ pub trait Clone : Sized { /// but can be overridden to reuse the resources of `a` to avoid unnecessary /// allocations. #[inline(always)] - #[unstable(feature = "core", - reason = "this function is rarely used")] + #[stable(feature = "rust1", since = "1.0.0")] fn clone_from(&mut self, source: &Self) { *self = source.clone() } From 561fdec1350056d77245a17d59c7d740c95621d1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 8 Apr 2015 16:41:14 -0700 Subject: [PATCH 43/62] std: Stabilize io::Error::from_raw_os_error This commit stabilizes the old `io::Error::from_os_error` after being renamed to use the `raw_os_error` terminology instead. This function is often useful when writing bindings to OS functions but only actually converting to an I/O error at a later point. --- src/libstd/io/error.rs | 12 +++++++++--- src/libstd/sys/unix/process2.rs | 2 +- src/libstd/sys/unix/thread.rs | 2 +- src/libstd/sys/windows/net.rs | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index b84dcb8fb6206..7428d0a8e35ef 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -163,12 +163,18 @@ impl Error { /// `Error` for the error code. #[stable(feature = "rust1", since = "1.0.0")] pub fn last_os_error() -> Error { - Error::from_os_error(sys::os::errno() as i32) + Error::from_raw_os_error(sys::os::errno() as i32) } /// Creates a new instance of an `Error` from a particular OS error code. - #[unstable(feature = "io", - reason = "unclear whether this function is necessary")] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn from_raw_os_error(code: i32) -> Error { + Error { repr: Repr::Os(code) } + } + + /// Creates a new instance of an `Error` from a particular OS error code. + #[unstable(feature = "io", reason = "deprecated")] + #[deprecated(since = "1.0.0", reason = "renamed to from_raw_os_error")] pub fn from_os_error(code: i32) -> Error { Error { repr: Repr::Os(code) } } diff --git a/src/libstd/sys/unix/process2.rs b/src/libstd/sys/unix/process2.rs index c2a8b26aef4eb..60f00c80b4abd 100644 --- a/src/libstd/sys/unix/process2.rs +++ b/src/libstd/sys/unix/process2.rs @@ -193,7 +193,7 @@ impl Process { let errno = combine(&bytes[0.. 4]); assert!(p.wait().is_ok(), "wait() should either return Ok or panic"); - return Err(Error::from_os_error(errno)) + return Err(Error::from_raw_os_error(errno)) } Ok(0) => return Ok(p), Err(ref e) if e.kind() == ErrorKind::Interrupted => {} diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index eb61f21aacd5d..73d6cd73621ad 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -212,7 +212,7 @@ pub unsafe fn create(stack: usize, p: Thunk) -> io::Result { assert_eq!(pthread_attr_destroy(&mut attr), 0); return if ret != 0 { - Err(io::Error::from_os_error(ret)) + Err(io::Error::from_raw_os_error(ret)) } else { mem::forget(p); // ownership passed to pthread_create Ok(native) diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index 12a8ef99d764a..5ced8863e62a9 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -43,7 +43,7 @@ pub fn init() { /// Returns the last error from the Windows socket interface. fn last_error() -> io::Error { - io::Error::from_os_error(unsafe { c::WSAGetLastError() }) + io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) } /// Checks if the signed integer is the Windows constant `SOCKET_ERROR` (-1) From ec7c800d2fc0dc5918d325ae68d88c9708d20259 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 8 Apr 2015 16:27:10 -0700 Subject: [PATCH 44/62] Remove pretty-expanded from failing tests This commit removes pretty-expanded from all tests that wind up calling panic! one way or another now that its internals are unstable. --- src/test/run-pass-fulldeps/rename-directory.rs | 1 - src/test/run-pass/argument-passing.rs | 1 - src/test/run-pass/arith-2.rs | 1 - src/test/run-pass/arith-unsigned.rs | 1 - src/test/run-pass/artificial-block.rs | 1 - src/test/run-pass/as-precedence.rs | 1 - src/test/run-pass/asm-in-out-operand.rs | 1 - src/test/run-pass/asm-out-assign.rs | 1 - src/test/run-pass/assign-assign.rs | 1 - src/test/run-pass/assignability-trait.rs | 1 - src/test/run-pass/associated-types-basic.rs | 1 - src/test/run-pass/associated-types-binding-in-trait.rs | 1 - src/test/run-pass/associated-types-bound.rs | 1 - src/test/run-pass/associated-types-constant-type.rs | 1 - src/test/run-pass/associated-types-doubleendediterator-object.rs | 1 - src/test/run-pass/associated-types-enum-field-named.rs | 1 - src/test/run-pass/associated-types-enum-field-numbered.rs | 1 - src/test/run-pass/associated-types-in-default-method.rs | 1 - src/test/run-pass/associated-types-in-fn.rs | 1 - src/test/run-pass/associated-types-in-impl-generics.rs | 1 - src/test/run-pass/associated-types-in-inherent-method.rs | 1 - src/test/run-pass/associated-types-issue-20220.rs | 1 - src/test/run-pass/associated-types-issue-21212.rs | 1 - src/test/run-pass/associated-types-iterator-binding.rs | 1 - ...ed-types-project-from-type-param-via-bound-in-where-clause.rs | 1 - .../associated-types-projection-from-known-type-in-impl.rs | 1 - src/test/run-pass/associated-types-projection-in-supertrait.rs | 1 - src/test/run-pass/associated-types-ref-in-struct-literal.rs | 1 - src/test/run-pass/associated-types-return.rs | 1 - src/test/run-pass/associated-types-simple.rs | 1 - src/test/run-pass/associated-types-stream.rs | 1 - src/test/run-pass/associated-types-struct-field-named.rs | 1 - src/test/run-pass/associated-types-struct-field-numbered.rs | 1 - src/test/run-pass/associated-types-sugar-path.rs | 1 - src/test/run-pass/attr-main-2.rs | 1 - src/test/run-pass/attr-no-drop-flag-size.rs | 1 - src/test/run-pass/auto-loop.rs | 1 - src/test/run-pass/auto-ref-sliceable.rs | 1 - src/test/run-pass/autobind.rs | 1 - src/test/run-pass/autoderef-method-on-trait.rs | 1 - src/test/run-pass/autoderef-method-priority.rs | 1 - src/test/run-pass/autoderef-method-twice-but-not-thrice.rs | 1 - src/test/run-pass/autoderef-method-twice.rs | 1 - src/test/run-pass/autoderef-method.rs | 1 - src/test/run-pass/autoref-intermediate-types-issue-3585.rs | 1 - src/test/run-pass/big-literals.rs | 1 - src/test/run-pass/binary-minus-without-space.rs | 1 - src/test/run-pass/bind-by-move.rs | 1 - src/test/run-pass/bind-field-short-with-modifiers.rs | 1 - src/test/run-pass/block-arg-call-as.rs | 1 - src/test/run-pass/block-expr-precedence.rs | 1 - src/test/run-pass/block-fn-coerce.rs | 1 - src/test/run-pass/bool-not.rs | 1 - src/test/run-pass/bool.rs | 1 - src/test/run-pass/borrow-tuple-fields.rs | 1 - src/test/run-pass/borrowck-borrow-from-expr-block.rs | 1 - src/test/run-pass/borrowck-closures-two-imm.rs | 1 - src/test/run-pass/borrowck-fixed-length-vecs.rs | 1 - src/test/run-pass/borrowck-freeze-frozen-mut.rs | 1 - src/test/run-pass/borrowck-macro-interaction-issue-6304.rs | 1 - src/test/run-pass/borrowck-move-by-capture-ok.rs | 1 - src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs | 1 - src/test/run-pass/borrowck-pat-reassign-no-binding.rs | 1 - src/test/run-pass/borrowck-rvalues-mutable.rs | 1 - src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs | 1 - src/test/run-pass/borrowck-univariant-enum.rs | 1 - src/test/run-pass/borrowed-ptr-pattern-2.rs | 1 - src/test/run-pass/borrowed-ptr-pattern-3.rs | 1 - src/test/run-pass/borrowed-ptr-pattern-infallible.rs | 1 - src/test/run-pass/borrowed-ptr-pattern-option.rs | 1 - src/test/run-pass/borrowed-ptr-pattern.rs | 1 - src/test/run-pass/break.rs | 1 - src/test/run-pass/bug-7183-generics.rs | 1 - src/test/run-pass/builtin-superkinds-capabilities-transitive.rs | 1 - src/test/run-pass/builtin-superkinds-capabilities-xc.rs | 1 - src/test/run-pass/builtin-superkinds-capabilities.rs | 1 - src/test/run-pass/builtin-superkinds-self-type.rs | 1 - src/test/run-pass/by-value-self-in-mut-slot.rs | 1 - src/test/run-pass/call-closure-from-overloaded-op.rs | 1 - src/test/run-pass/capture-clauses-boxed-closures.rs | 1 - src/test/run-pass/capture-clauses-unboxed-closures.rs | 1 - src/test/run-pass/cast.rs | 1 - src/test/run-pass/cci_nested_exe.rs | 1 - src/test/run-pass/cell-does-not-clone.rs | 1 - src/test/run-pass/cfg-macros-foo.rs | 1 - src/test/run-pass/cfg-macros-notfoo.rs | 1 - src/test/run-pass/cfgs-on-items.rs | 1 - src/test/run-pass/char.rs | 1 - src/test/run-pass/check-static-mut-slices.rs | 1 - src/test/run-pass/check-static-slice.rs | 1 - src/test/run-pass/class-exports.rs | 1 - src/test/run-pass/class-method-cross-crate.rs | 1 - src/test/run-pass/class-methods-cross-crate.rs | 1 - src/test/run-pass/class-methods.rs | 1 - src/test/run-pass/class-poly-methods-cross-crate.rs | 1 - src/test/run-pass/class-poly-methods.rs | 1 - src/test/run-pass/classes-cross-crate.rs | 1 - src/test/run-pass/classes-simple-cross-crate.rs | 1 - src/test/run-pass/classes-simple-method.rs | 1 - src/test/run-pass/classes-simple.rs | 1 - src/test/run-pass/cleanup-rvalue-during-if-and-while.rs | 1 - src/test/run-pass/cleanup-rvalue-temp-during-incomplete-alloc.rs | 1 - src/test/run-pass/closure-inference.rs | 1 - src/test/run-pass/closure-inference2.rs | 1 - src/test/run-pass/cmp-default.rs | 1 - src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs | 1 - src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs | 1 - src/test/run-pass/coerce-reborrow-mut-vec-arg.rs | 1 - src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs | 1 - src/test/run-pass/compare-generic-enums.rs | 1 - src/test/run-pass/concat.rs | 1 - src/test/run-pass/conditional-compile.rs | 1 - src/test/run-pass/conditional-debug-macro-off.rs | 1 - src/test/run-pass/const-autoderef.rs | 1 - src/test/run-pass/const-big-enum.rs | 1 - src/test/run-pass/const-binops.rs | 1 - src/test/run-pass/const-block-cross-crate-fn.rs | 1 - src/test/run-pass/const-block-item-macro-codegen.rs | 1 - src/test/run-pass/const-block-item.rs | 1 - src/test/run-pass/const-block.rs | 1 - src/test/run-pass/const-cast-ptr-int.rs | 1 - src/test/run-pass/const-cast.rs | 1 - src/test/run-pass/const-const.rs | 1 - src/test/run-pass/const-contents.rs | 1 - src/test/run-pass/const-cross-crate-const.rs | 1 - src/test/run-pass/const-cross-crate-extern.rs | 1 - src/test/run-pass/const-deref.rs | 1 - src/test/run-pass/const-enum-byref-self.rs | 1 - src/test/run-pass/const-enum-byref.rs | 1 - src/test/run-pass/const-enum-cast.rs | 1 - src/test/run-pass/const-enum-ptr.rs | 1 - src/test/run-pass/const-enum-struct.rs | 1 - src/test/run-pass/const-enum-struct2.rs | 1 - src/test/run-pass/const-enum-structlike.rs | 1 - src/test/run-pass/const-enum-tuple.rs | 1 - src/test/run-pass/const-enum-tuple2.rs | 1 - src/test/run-pass/const-enum-tuplestruct.rs | 1 - src/test/run-pass/const-enum-tuplestruct2.rs | 1 - src/test/run-pass/const-enum-vec-index.rs | 1 - src/test/run-pass/const-enum-vec-ptr.rs | 1 - src/test/run-pass/const-enum-vector.rs | 1 - src/test/run-pass/const-extern-function.rs | 1 - src/test/run-pass/const-fn-val.rs | 1 - src/test/run-pass/const-negative.rs | 1 - src/test/run-pass/const-nullary-enum.rs | 1 - src/test/run-pass/const-nullary-univariant-enum.rs | 1 - src/test/run-pass/const-region-ptrs-noncopy.rs | 1 - src/test/run-pass/const-str-ptr.rs | 1 - src/test/run-pass/const-tuple-struct.rs | 1 - src/test/run-pass/consts-in-patterns.rs | 1 - src/test/run-pass/cross-crate-newtype-struct-pat.rs | 1 - src/test/run-pass/deep.rs | 1 - src/test/run-pass/deref-mut-on-ref.rs | 1 - src/test/run-pass/deref-on-ref.rs | 1 - src/test/run-pass/deref-rc.rs | 1 - src/test/run-pass/deriving-cmp-generic-enum.rs | 1 - src/test/run-pass/deriving-cmp-generic-struct-enum.rs | 1 - src/test/run-pass/deriving-cmp-generic-struct.rs | 1 - src/test/run-pass/deriving-cmp-generic-tuple-struct.rs | 1 - src/test/run-pass/deriving-cmp-shortcircuit.rs | 1 - src/test/run-pass/deriving-default-box.rs | 1 - src/test/run-pass/deriving-encodable-decodable-box.rs | 1 - src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs | 1 - src/test/run-pass/deriving-hash.rs | 1 - src/test/run-pass/deriving-rand.rs | 1 - src/test/run-pass/destructure-array-1.rs | 1 - src/test/run-pass/die-macro.rs | 1 - src/test/run-pass/div-mod.rs | 1 - src/test/run-pass/drop-struct-as-object.rs | 1 - src/test/run-pass/drop-with-type-ascription-1.rs | 1 - src/test/run-pass/drop-with-type-ascription-2.rs | 1 - src/test/run-pass/dropck_tarena_sound_drop.rs | 1 - src/test/run-pass/dst-deref-mut.rs | 1 - src/test/run-pass/dst-deref.rs | 1 - src/test/run-pass/dst-index.rs | 1 - src/test/run-pass/dst-raw.rs | 1 - src/test/run-pass/dst-struct-sole.rs | 1 - src/test/run-pass/dst-struct.rs | 1 - src/test/run-pass/dst-trait.rs | 1 - src/test/run-pass/else-if.rs | 1 - src/test/run-pass/empty-allocation-non-null.rs | 1 - src/test/run-pass/enum-alignment.rs | 1 - src/test/run-pass/enum-clike-ffi-as-int.rs | 1 - src/test/run-pass/enum-discr.rs | 1 - src/test/run-pass/enum-discrim-autosizing.rs | 1 - src/test/run-pass/enum-discrim-manual-sizing.rs | 1 - src/test/run-pass/enum-disr-val-pretty.rs | 1 - src/test/run-pass/enum-null-pointer-opt.rs | 1 - src/test/run-pass/enum-nullable-const-null-with-fields.rs | 1 - src/test/run-pass/enum-nullable-simplifycfg-misopt.rs | 1 - src/test/run-pass/env-home-dir.rs | 1 - src/test/run-pass/env-vars.rs | 1 - src/test/run-pass/eq-multidispatch.rs | 1 - src/test/run-pass/estr-uniq.rs | 1 - src/test/run-pass/exec-env.rs | 1 - src/test/run-pass/explicit-self-generic.rs | 1 - src/test/run-pass/explicit-self-objects-uniq.rs | 1 - src/test/run-pass/explicit-self.rs | 1 - src/test/run-pass/expr-block-fn.rs | 1 - src/test/run-pass/expr-block-generic-unique2.rs | 1 - src/test/run-pass/expr-block-generic.rs | 1 - src/test/run-pass/expr-block-slot.rs | 1 - src/test/run-pass/expr-block-unique.rs | 1 - src/test/run-pass/expr-block.rs | 1 - src/test/run-pass/expr-copy.rs | 1 - src/test/run-pass/expr-fn.rs | 1 - src/test/run-pass/expr-if-generic.rs | 1 - src/test/run-pass/expr-if-panic-all.rs | 1 - src/test/run-pass/expr-if-panic.rs | 1 - src/test/run-pass/expr-if-unique.rs | 1 - src/test/run-pass/expr-if.rs | 1 - src/test/run-pass/expr-match-generic-unique1.rs | 1 - src/test/run-pass/expr-match-generic-unique2.rs | 1 - src/test/run-pass/expr-match-generic.rs | 1 - src/test/run-pass/expr-match-panic-all.rs | 1 - src/test/run-pass/expr-match-panic.rs | 1 - src/test/run-pass/expr-match-unique.rs | 1 - src/test/run-pass/expr-match.rs | 1 - src/test/run-pass/ext-expand-inner-exprs.rs | 1 - src/test/run-pass/exterior.rs | 1 - src/test/run-pass/extern-call-direct.rs | 1 - src/test/run-pass/extern-compare-with-return-type.rs | 1 - src/test/run-pass/extern-methods.rs | 1 - src/test/run-pass/extern-pass-char.rs | 1 - src/test/run-pass/extern-pass-double.rs | 1 - src/test/run-pass/extern-pass-u32.rs | 1 - src/test/run-pass/extern-pass-u64.rs | 1 - src/test/run-pass/extern-return-TwoU16s.rs | 1 - src/test/run-pass/extern-return-TwoU32s.rs | 1 - src/test/run-pass/extern-return-TwoU64s.rs | 1 - src/test/run-pass/extern-return-TwoU8s.rs | 1 - src/test/run-pass/extern-take-value.rs | 1 - src/test/run-pass/extoption_env-not-defined.rs | 1 - src/test/run-pass/field-destruction-order.rs | 1 - src/test/run-pass/fixed_length_copy.rs | 1 - src/test/run-pass/float2.rs | 1 - src/test/run-pass/floatlits.rs | 1 - src/test/run-pass/fn-bare-assign.rs | 1 - src/test/run-pass/fn-bare-size.rs | 1 - src/test/run-pass/fn-bare-spawn.rs | 1 - src/test/run-pass/fn-item-type-cast.rs | 1 - src/test/run-pass/fn-pattern-expected-type.rs | 1 - src/test/run-pass/for-destruct.rs | 1 - src/test/run-pass/for-loop-goofiness.rs | 1 - src/test/run-pass/for-loop-into-iterator.rs | 1 - src/test/run-pass/for-loop-panic.rs | 1 - src/test/run-pass/foreach-external-iterators-break.rs | 1 - .../run-pass/foreach-external-iterators-hashmap-break-restart.rs | 1 - src/test/run-pass/foreach-external-iterators-hashmap.rs | 1 - src/test/run-pass/foreach-external-iterators-loop.rs | 1 - src/test/run-pass/foreach-external-iterators-nested.rs | 1 - src/test/run-pass/foreach-external-iterators.rs | 1 - src/test/run-pass/foreach-nested.rs | 1 - src/test/run-pass/foreign-fn-with-byval.rs | 1 - src/test/run-pass/format-nan.rs | 1 - src/test/run-pass/format-ref-cell.rs | 1 - src/test/run-pass/fsu-moves-and-copies.rs | 1 - src/test/run-pass/fun-call-variants.rs | 1 - src/test/run-pass/fun-indirect-call.rs | 1 - src/test/run-pass/func-arg-incomplete-pattern.rs | 1 - src/test/run-pass/func-arg-ref-pattern.rs | 1 - src/test/run-pass/func-arg-wild-pattern.rs | 1 - src/test/run-pass/generic-exterior-unique.rs | 1 - src/test/run-pass/generic-extern-mangle.rs | 1 - src/test/run-pass/generic-fn-infer.rs | 1 - src/test/run-pass/generic-object.rs | 1 - src/test/run-pass/generic-static-methods.rs | 1 - src/test/run-pass/generic-type.rs | 1 - src/test/run-pass/generic-unique.rs | 1 - src/test/run-pass/getopts_ref.rs | 1 - src/test/run-pass/global-scope.rs | 1 - src/test/run-pass/guards-not-exhaustive.rs | 1 - src/test/run-pass/guards.rs | 1 - src/test/run-pass/hrtb-fn-like-trait-object.rs | 1 - src/test/run-pass/hrtb-fn-like-trait.rs | 1 - src/test/run-pass/hrtb-trait-object-paren-notation.rs | 1 - src/test/run-pass/huge-largest-array.rs | 1 - src/test/run-pass/hygiene-dodging-1.rs | 1 - src/test/run-pass/hygienic-labels.rs | 1 - src/test/run-pass/i32-sub.rs | 1 - src/test/run-pass/i8-incr.rs | 1 - src/test/run-pass/if-let.rs | 1 - src/test/run-pass/impl-inherent-non-conflict.rs | 1 - src/test/run-pass/impl-inherent-prefer-over-trait.rs | 1 - src/test/run-pass/impl-not-adjacent-to-type.rs | 1 - src/test/run-pass/import-glob-crate.rs | 1 - src/test/run-pass/inferred-suffix-in-pattern-range.rs | 1 - src/test/run-pass/inherent-trait-method-order.rs | 1 - src/test/run-pass/init-res-into-things.rs | 1 - src/test/run-pass/inner-attrs-on-impl.rs | 1 - src/test/run-pass/inner-static.rs | 1 - src/test/run-pass/integer-literal-radix.rs | 1 - src/test/run-pass/intrinsic-alignment.rs | 1 - src/test/run-pass/intrinsic-assume.rs | 1 - src/test/run-pass/intrinsic-atomics-cc.rs | 1 - src/test/run-pass/intrinsic-atomics.rs | 1 - src/test/run-pass/intrinsic-move-val.rs | 1 - src/test/run-pass/intrinsic-return-address.rs | 1 - src/test/run-pass/intrinsic-unreachable.rs | 1 - src/test/run-pass/intrinsics-integer.rs | 1 - src/test/run-pass/intrinsics-math.rs | 1 - src/test/run-pass/issue-10392.rs | 1 - src/test/run-pass/issue-10734.rs | 1 - src/test/run-pass/issue-10802.rs | 1 - src/test/run-pass/issue-1112.rs | 1 - src/test/run-pass/issue-11552.rs | 1 - src/test/run-pass/issue-11577.rs | 1 - src/test/run-pass/issue-11677.rs | 1 - src/test/run-pass/issue-11940.rs | 1 - src/test/run-pass/issue-12285.rs | 1 - src/test/run-pass/issue-12677.rs | 1 - src/test/run-pass/issue-13204.rs | 1 - src/test/run-pass/issue-13323.rs | 1 - src/test/run-pass/issue-13507-2.rs | 1 - src/test/run-pass/issue-13867.rs | 1 - src/test/run-pass/issue-14308.rs | 1 - src/test/run-pass/issue-14456.rs | 1 - src/test/run-pass/issue-14865.rs | 1 - src/test/run-pass/issue-14936.rs | 1 - src/test/run-pass/issue-14940.rs | 1 - src/test/run-pass/issue-15080.rs | 1 - src/test/run-pass/issue-15104.rs | 1 - src/test/run-pass/issue-15129.rs | 1 - src/test/run-pass/issue-15149.rs | 1 - src/test/run-pass/issue-15673.rs | 1 - src/test/run-pass/issue-15689-1.rs | 1 - src/test/run-pass/issue-15734.rs | 1 - src/test/run-pass/issue-15793.rs | 1 - src/test/run-pass/issue-15858.rs | 1 - src/test/run-pass/issue-15881-model-lexer-dotdotdot.rs | 1 - src/test/run-pass/issue-16151.rs | 1 - src/test/run-pass/issue-16530.rs | 1 - src/test/run-pass/issue-16560.rs | 1 - src/test/run-pass/issue-16596.rs | 1 - src/test/run-pass/issue-16648.rs | 1 - src/test/run-pass/issue-16739.rs | 1 - src/test/run-pass/issue-16774.rs | 1 - src/test/run-pass/issue-1701.rs | 1 - src/test/run-pass/issue-17068.rs | 1 - src/test/run-pass/issue-17074.rs | 1 - src/test/run-pass/issue-17216.rs | 1 - src/test/run-pass/issue-17233.rs | 1 - src/test/run-pass/issue-17302.rs | 1 - src/test/run-pass/issue-17662.rs | 1 - src/test/run-pass/issue-17718-parse-const.rs | 1 - src/test/run-pass/issue-17718.rs | 1 - src/test/run-pass/issue-17734.rs | 1 - src/test/run-pass/issue-17877.rs | 1 - src/test/run-pass/issue-18352.rs | 1 - src/test/run-pass/issue-18412.rs | 1 - src/test/run-pass/issue-18652.rs | 1 - src/test/run-pass/issue-18767.rs | 1 - src/test/run-pass/issue-18859.rs | 1 - src/test/run-pass/issue-19244.rs | 1 - src/test/run-pass/issue-19811-escape-unicode.rs | 1 - src/test/run-pass/issue-21058.rs | 1 - src/test/run-pass/issue-21306.rs | 1 - src/test/run-pass/issue-21361.rs | 1 - src/test/run-pass/issue-21384.rs | 1 - src/test/run-pass/issue-21634.rs | 1 - src/test/run-pass/issue-21655.rs | 1 - src/test/run-pass/issue-21721.rs | 1 - src/test/run-pass/issue-22036.rs | 1 - src/test/run-pass/issue-2214.rs | 1 - src/test/run-pass/issue-22536-copy-mustnt-zero.rs | 1 - src/test/run-pass/issue-2311-2.rs | 1 - src/test/run-pass/issue-2312.rs | 1 - src/test/run-pass/issue-2428.rs | 1 - src/test/run-pass/issue-2611-3.rs | 1 - src/test/run-pass/issue-2735-2.rs | 1 - src/test/run-pass/issue-2735-3.rs | 1 - src/test/run-pass/issue-2748-b.rs | 1 - src/test/run-pass/issue-2895.rs | 1 - src/test/run-pass/issue-2936.rs | 1 - src/test/run-pass/issue-3091.rs | 1 - src/test/run-pass/issue-3290.rs | 1 - src/test/run-pass/issue-333.rs | 1 - src/test/run-pass/issue-3574.rs | 1 - src/test/run-pass/issue-3895.rs | 1 - src/test/run-pass/issue-3935.rs | 1 - src/test/run-pass/issue-3979-generics.rs | 1 - src/test/run-pass/issue-3979-xcrate.rs | 1 - src/test/run-pass/issue-3979.rs | 1 - src/test/run-pass/issue-4016.rs | 1 - src/test/run-pass/issue-4107.rs | 1 - src/test/run-pass/issue-4448.rs | 1 - src/test/run-pass/issue-4734.rs | 1 - src/test/run-pass/issue-5239-2.rs | 1 - src/test/run-pass/issue-5521.rs | 1 - src/test/run-pass/issue-5530.rs | 1 - src/test/run-pass/issue-5917.rs | 1 - src/test/run-pass/issue-5997.rs | 1 - src/test/run-pass/issue-6128.rs | 1 - src/test/run-pass/issue-6130.rs | 1 - src/test/run-pass/issue-6153.rs | 1 - src/test/run-pass/issue-6334.rs | 1 - src/test/run-pass/issue-6449.rs | 1 - src/test/run-pass/issue-6892.rs | 1 - src/test/run-pass/issue-7575.rs | 1 - src/test/run-pass/issue-7663.rs | 1 - src/test/run-pass/issue-7784.rs | 1 - src/test/run-pass/issue-8351-1.rs | 1 - src/test/run-pass/issue-8351-2.rs | 1 - src/test/run-pass/issue-8391.rs | 1 - src/test/run-pass/issue-8460.rs | 1 - src/test/run-pass/issue-8498.rs | 1 - src/test/run-pass/issue-8709.rs | 1 - src/test/run-pass/issue-8860.rs | 1 - src/test/run-pass/issue-8898.rs | 1 - src/test/run-pass/issue-9188.rs | 1 - src/test/run-pass/issue-9259.rs | 1 - src/test/run-pass/issue-9394-inherited-trait-calls.rs | 1 - src/test/run-pass/issue-979.rs | 1 - src/test/run-pass/issue-9918.rs | 1 - src/test/run-pass/iter-cloned-type-inference.rs | 1 - src/test/run-pass/kindck-owned-trait-contains-1.rs | 1 - src/test/run-pass/last-use-in-block.rs | 1 - src/test/run-pass/last-use-in-cap-clause.rs | 1 - src/test/run-pass/let-destruct-ref.rs | 1 - src/test/run-pass/let-var-hygiene.rs | 1 - src/test/run-pass/logging-enabled-debug.rs | 1 - src/test/run-pass/logging-enabled.rs | 1 - src/test/run-pass/loop-break-cont-1.rs | 1 - src/test/run-pass/loop-scope.rs | 1 - src/test/run-pass/macro-block-nonterminal.rs | 1 - src/test/run-pass/macro-crate-def-only.rs | 1 - src/test/run-pass/macro-crate-use.rs | 1 - src/test/run-pass/macro-deep_expansion.rs | 1 - src/test/run-pass/macro-interpolation.rs | 1 - src/test/run-pass/macro-method-issue-4621.rs | 1 - src/test/run-pass/macro-of-higher-order.rs | 1 - src/test/run-pass/macro-pat.rs | 1 - src/test/run-pass/macro-path.rs | 1 - src/test/run-pass/macro-with-attrs1.rs | 1 - src/test/run-pass/macro-with-attrs2.rs | 1 - src/test/run-pass/match-arm-statics.rs | 1 - src/test/run-pass/match-borrowed_str.rs | 1 - src/test/run-pass/match-bot-2.rs | 1 - src/test/run-pass/match-enum-struct-0.rs | 1 - src/test/run-pass/match-enum-struct-1.rs | 1 - src/test/run-pass/match-implicit-copy-unique.rs | 1 - src/test/run-pass/match-in-macro.rs | 1 - src/test/run-pass/match-pattern-bindings.rs | 1 - src/test/run-pass/match-pipe-binding.rs | 1 - src/test/run-pass/match-ref-binding-in-guard-3256.rs | 1 - src/test/run-pass/match-ref-binding-mut-option.rs | 1 - src/test/run-pass/match-ref-binding-mut.rs | 1 - src/test/run-pass/match-ref-binding.rs | 1 - src/test/run-pass/match-static-const-rename.rs | 1 - src/test/run-pass/match-str.rs | 1 - src/test/run-pass/match-struct-0.rs | 1 - src/test/run-pass/match-tag.rs | 1 - src/test/run-pass/match-vec-alternatives.rs | 1 - src/test/run-pass/match-vec-rvalue.rs | 1 - src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs | 1 - src/test/run-pass/method-projection.rs | 1 - src/test/run-pass/method-self-arg-aux1.rs | 1 - src/test/run-pass/method-self-arg-aux2.rs | 1 - src/test/run-pass/method-self-arg-trait.rs | 1 - src/test/run-pass/method-self-arg.rs | 1 - src/test/run-pass/method-two-trait-defer-resolution-1.rs | 1 - src/test/run-pass/method-two-trait-defer-resolution-2.rs | 1 - src/test/run-pass/method-where-clause.rs | 1 - src/test/run-pass/mod-inside-fn.rs | 1 - src/test/run-pass/monad.rs | 1 - src/test/run-pass/move-1-unique.rs | 1 - src/test/run-pass/move-2-unique.rs | 1 - src/test/run-pass/move-2.rs | 1 - src/test/run-pass/move-3-unique.rs | 1 - src/test/run-pass/move-4-unique.rs | 1 - src/test/run-pass/move-4.rs | 1 - src/test/run-pass/move-arg-2-unique.rs | 1 - src/test/run-pass/move-arg-2.rs | 1 - src/test/run-pass/move-arg.rs | 1 - src/test/run-pass/move-out-of-field.rs | 1 - src/test/run-pass/move-scalar.rs | 1 - src/test/run-pass/multi-let.rs | 1 - src/test/run-pass/multidispatch1.rs | 1 - src/test/run-pass/multidispatch2.rs | 1 - src/test/run-pass/mut-function-arguments.rs | 1 - src/test/run-pass/mut-in-ident-patterns.rs | 1 - .../run-pass/mutability-inherits-through-fixed-length-vec.rs | 1 - src/test/run-pass/negative.rs | 1 - src/test/run-pass/nested-class.rs | 1 - src/test/run-pass/nested-function-names-issue-8587.rs | 1 - src/test/run-pass/nested_item_main.rs | 1 - src/test/run-pass/new-unicode-escapes.rs | 1 - src/test/run-pass/newlambdas.rs | 1 - src/test/run-pass/newtype-polymorphic.rs | 1 - src/test/run-pass/newtype-struct-drop-run.rs | 1 - src/test/run-pass/no-landing-pads.rs | 1 - src/test/run-pass/non-legacy-modes.rs | 1 - src/test/run-pass/nul-characters.rs | 1 - src/test/run-pass/nullable-pointer-ffi-compat.rs | 1 - src/test/run-pass/nullable-pointer-iotareduction.rs | 1 - src/test/run-pass/nullable-pointer-size.rs | 1 - src/test/run-pass/nullary-or-pattern.rs | 1 - src/test/run-pass/numeric-method-autoexport.rs | 1 - src/test/run-pass/object-method-numbering.rs | 1 - src/test/run-pass/object-safety-sized-self-by-value-self.rs | 1 - src/test/run-pass/object-safety-sized-self-generic-method.rs | 1 - src/test/run-pass/object-safety-sized-self-return-Self.rs | 1 - src/test/run-pass/objects-coerce-freeze-borrored.rs | 1 - .../run-pass/objects-owned-object-borrowed-method-headerless.rs | 1 - src/test/run-pass/objects-owned-object-owned-method.rs | 1 - src/test/run-pass/once-move-out-on-heap.rs | 1 - src/test/run-pass/one-tuple.rs | 1 - src/test/run-pass/operator-associativity.rs | 1 - src/test/run-pass/option-unwrap.rs | 1 - src/test/run-pass/or-pattern.rs | 1 - src/test/run-pass/order-drop-with-match.rs | 1 - src/test/run-pass/out-pointer-aliasing.rs | 1 - src/test/run-pass/overloaded-autoderef-indexing.rs | 1 - src/test/run-pass/overloaded-autoderef-order.rs | 1 - src/test/run-pass/overloaded-autoderef-vtable.rs | 1 - src/test/run-pass/overloaded-autoderef-xcrate.rs | 1 - src/test/run-pass/overloaded-calls-object-one-arg.rs | 1 - src/test/run-pass/overloaded-calls-object-two-args.rs | 1 - src/test/run-pass/overloaded-calls-object-zero-args.rs | 1 - src/test/run-pass/overloaded-calls-simple.rs | 1 - src/test/run-pass/overloaded-calls-zero-args.rs | 1 - src/test/run-pass/overloaded-deref-count.rs | 1 - src/test/run-pass/overloaded-index-assoc-list.rs | 1 - src/test/run-pass/overloaded-index-autoderef.rs | 1 - src/test/run-pass/overloaded-index-in-field.rs | 1 - src/test/run-pass/overloaded-index.rs | 1 - src/test/run-pass/packed-struct-borrow-element.rs | 1 - src/test/run-pass/packed-struct-generic-layout.rs | 1 - src/test/run-pass/packed-struct-generic-size.rs | 1 - src/test/run-pass/packed-struct-layout.rs | 1 - src/test/run-pass/packed-struct-match.rs | 1 - src/test/run-pass/packed-struct-size-xc.rs | 1 - src/test/run-pass/packed-struct-size.rs | 1 - src/test/run-pass/packed-tuple-struct-layout.rs | 1 - src/test/run-pass/packed-tuple-struct-size.rs | 1 - src/test/run-pass/panic-in-dtor-drops-fields.rs | 1 - src/test/run-pass/pattern-bound-var-in-for-each.rs | 1 - src/test/run-pass/private-class-field.rs | 1 - src/test/run-pass/process-remove-from-env.rs | 1 - src/test/run-pass/range-type-infer.rs | 1 - src/test/run-pass/range.rs | 1 - src/test/run-pass/ranges-precedence.rs | 1 - src/test/run-pass/readalias.rs | 1 - src/test/run-pass/rec-extend.rs | 1 - src/test/run-pass/rec-tup.rs | 1 - src/test/run-pass/rec.rs | 1 - src/test/run-pass/record-pat.rs | 1 - src/test/run-pass/reexported-static-methods-cross-crate.rs | 1 - src/test/run-pass/regions-borrow-evec-fixed.rs | 1 - src/test/run-pass/regions-borrow-evec-uniq.rs | 1 - src/test/run-pass/regions-borrow-uniq.rs | 1 - src/test/run-pass/regions-bot.rs | 1 - .../run-pass/regions-close-over-type-parameter-successfully.rs | 1 - src/test/run-pass/regions-copy-closure.rs | 1 - src/test/run-pass/regions-dependent-addr-of.rs | 1 - src/test/run-pass/regions-early-bound-trait-param.rs | 1 - src/test/run-pass/regions-early-bound-used-in-bound-method.rs | 1 - src/test/run-pass/regions-early-bound-used-in-bound.rs | 1 - src/test/run-pass/regions-early-bound-used-in-type-param.rs | 1 - src/test/run-pass/regions-escape-into-other-fn.rs | 1 - src/test/run-pass/regions-infer-borrow-scope-addr-of.rs | 1 - src/test/run-pass/regions-infer-borrow-scope-view.rs | 1 - src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs | 1 - src/test/run-pass/regions-infer-borrow-scope.rs | 1 - src/test/run-pass/regions-infer-call-2.rs | 1 - src/test/run-pass/regions-infer-call.rs | 1 - src/test/run-pass/regions-infer-contravariance-due-to-ret.rs | 1 - .../run-pass/regions-lifetime-static-items-enclosing-scopes.rs | 1 - src/test/run-pass/regions-no-variance-from-fn-generics.rs | 1 - src/test/run-pass/regions-params.rs | 1 - src/test/run-pass/regions-refcell.rs | 1 - ...ns-relate-bound-regions-on-closures-to-inference-variables.rs | 1 - src/test/run-pass/regions-return-interior-of-option.rs | 1 - src/test/run-pass/regions-trait-object-1.rs | 1 - src/test/run-pass/repeat-expr-in-static.rs | 1 - src/test/run-pass/resolve-issue-2428.rs | 1 - src/test/run-pass/resource-in-struct.rs | 1 - src/test/run-pass/return-from-closure.rs | 1 - src/test/run-pass/segfault-no-out-of-stack.rs | 1 - src/test/run-pass/self-in-mut-slot-default-method.rs | 1 - src/test/run-pass/self-in-mut-slot-immediate-value.rs | 1 - src/test/run-pass/self-re-assign.rs | 1 - src/test/run-pass/self-shadowing-import.rs | 1 - src/test/run-pass/send_str_hashmap.rs | 1 - src/test/run-pass/send_str_treemap.rs | 1 - src/test/run-pass/sendfn-is-a-block.rs | 1 - src/test/run-pass/sepcomp-cci.rs | 1 - src/test/run-pass/sepcomp-extern.rs | 1 - src/test/run-pass/sepcomp-fns-backwards.rs | 1 - src/test/run-pass/sepcomp-fns.rs | 1 - src/test/run-pass/sepcomp-lib.rs | 1 - src/test/run-pass/sepcomp-statics.rs | 1 - src/test/run-pass/sepcomp-unwind.rs | 1 - src/test/run-pass/seq-compare.rs | 1 - src/test/run-pass/shift-various-types.rs | 1 - src/test/run-pass/shift.rs | 1 - src/test/run-pass/signed-shift-const-eval.rs | 1 - src/test/run-pass/sigpipe-should-be-ignored.rs | 1 - src/test/run-pass/simd-binop.rs | 1 - src/test/run-pass/simd-generics.rs | 1 - src/test/run-pass/simd-size-align.rs | 1 - src/test/run-pass/slice-2.rs | 1 - src/test/run-pass/slice-panic-1.rs | 1 - src/test/run-pass/slice-panic-2.rs | 1 - src/test/run-pass/slice.rs | 1 - src/test/run-pass/small-enum-range-edge.rs | 1 - src/test/run-pass/spawn-types.rs | 1 - src/test/run-pass/stable-addr-of.rs | 1 - src/test/run-pass/static-function-pointer-xc.rs | 1 - src/test/run-pass/static-function-pointer.rs | 1 - src/test/run-pass/static-impl.rs | 1 - src/test/run-pass/static-method-in-trait-with-tps-intracrate.rs | 1 - src/test/run-pass/static-method-xcrate.rs | 1 - src/test/run-pass/static-methods-in-traits.rs | 1 - src/test/run-pass/static-mut-foreign.rs | 1 - src/test/run-pass/static-mut-xc.rs | 1 - src/test/run-pass/str-multiline.rs | 1 - src/test/run-pass/string-escapes.rs | 1 - src/test/run-pass/struct-aliases-xcrate.rs | 1 - src/test/run-pass/struct-aliases.rs | 1 - src/test/run-pass/struct-destructuring-cross-crate.rs | 1 - src/test/run-pass/struct-like-variant-match.rs | 1 - src/test/run-pass/struct-new-as-field-name.rs | 1 - src/test/run-pass/struct-order-of-eval-1.rs | 1 - src/test/run-pass/struct-order-of-eval-2.rs | 1 - src/test/run-pass/struct-order-of-eval-3.rs | 1 - src/test/run-pass/struct-order-of-eval-4.rs | 1 - src/test/run-pass/struct_variant_xc_match.rs | 1 - src/test/run-pass/supertrait-default-generics.rs | 1 - src/test/run-pass/swap-1.rs | 1 - src/test/run-pass/swap-2.rs | 1 - src/test/run-pass/syntax-extension-cfg.rs | 1 - src/test/run-pass/tag-align-dyn-u64.rs | 1 - src/test/run-pass/tag-align-dyn-variants.rs | 1 - src/test/run-pass/tag-align-u64.rs | 1 - src/test/run-pass/tag-variant-disr-val.rs | 1 - src/test/run-pass/tag.rs | 1 - src/test/run-pass/tail-direct.rs | 1 - src/test/run-pass/task-comm-5.rs | 1 - src/test/run-pass/task-comm-6.rs | 1 - src/test/run-pass/task-comm-chan-nil.rs | 1 - src/test/run-pass/terminate-in-initializer.rs | 1 - src/test/run-pass/trait-bounds.rs | 1 - src/test/run-pass/trait-default-method-bound-subst.rs | 1 - src/test/run-pass/trait-default-method-bound-subst2.rs | 1 - src/test/run-pass/trait-default-method-bound-subst3.rs | 1 - src/test/run-pass/trait-default-method-bound-subst4.rs | 1 - src/test/run-pass/trait-default-method-bound.rs | 1 - src/test/run-pass/trait-default-method-xc-2.rs | 1 - src/test/run-pass/trait-default-method-xc.rs | 1 - src/test/run-pass/trait-generic.rs | 1 - src/test/run-pass/trait-impl.rs | 1 - src/test/run-pass/trait-inheritance-auto-xc-2.rs | 1 - src/test/run-pass/trait-inheritance-auto-xc.rs | 1 - src/test/run-pass/trait-inheritance-auto.rs | 1 - src/test/run-pass/trait-inheritance-call-bound-inherited.rs | 1 - src/test/run-pass/trait-inheritance-call-bound-inherited2.rs | 1 - .../trait-inheritance-cast-without-call-to-supertrait.rs | 1 - src/test/run-pass/trait-inheritance-cast.rs | 1 - src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs | 1 - src/test/run-pass/trait-inheritance-cross-trait-call.rs | 1 - src/test/run-pass/trait-inheritance-diamond.rs | 1 - src/test/run-pass/trait-inheritance-multiple-inheritors.rs | 1 - src/test/run-pass/trait-inheritance-multiple-params.rs | 1 - src/test/run-pass/trait-inheritance-overloading-xc-exe.rs | 1 - src/test/run-pass/trait-inheritance-self-in-supertype.rs | 1 - src/test/run-pass/trait-inheritance-simple.rs | 1 - src/test/run-pass/trait-inheritance-static.rs | 1 - src/test/run-pass/trait-inheritance-static2.rs | 1 - src/test/run-pass/trait-inheritance-subst.rs | 1 - src/test/run-pass/trait-inheritance-subst2.rs | 1 - src/test/run-pass/trait-inheritance-visibility.rs | 1 - src/test/run-pass/trait-inheritance2.rs | 1 - src/test/run-pass/trait-object-generics.rs | 1 - src/test/run-pass/trait-object-with-lifetime-bound.rs | 1 - src/test/run-pass/trait-safety-ok-cc.rs | 1 - src/test/run-pass/trait-safety-ok.rs | 1 - src/test/run-pass/traits-assoc-type-in-supertrait.rs | 1 - src/test/run-pass/traits-conditional-dispatch.rs | 1 - src/test/run-pass/traits-conditional-model-fn.rs | 1 - src/test/run-pass/traits-default-method-macro.rs | 1 - src/test/run-pass/traits-multidispatch-infer-convert-target.rs | 1 - src/test/run-pass/traits-repeated-supertrait.rs | 1 - src/test/run-pass/trans-tag-static-padding.rs | 1 - src/test/run-pass/tup.rs | 1 - src/test/run-pass/tuple-index-fat-types.rs | 1 - src/test/run-pass/tuple-index.rs | 1 - src/test/run-pass/tydesc-name.rs | 1 - src/test/run-pass/type-id-higher-rank.rs | 1 - src/test/run-pass/type-namespace.rs | 1 - src/test/run-pass/type-sizes.rs | 1 - src/test/run-pass/typeck-macro-interaction-issue-8852.rs | 1 - src/test/run-pass/typeck_type_placeholder_1.rs | 1 - src/test/run-pass/typeid-intrinsic.rs | 1 - src/test/run-pass/typestate-multi-decl.rs | 1 - src/test/run-pass/u32-decr.rs | 1 - src/test/run-pass/u8-incr-decr.rs | 1 - src/test/run-pass/u8-incr.rs | 1 - src/test/run-pass/ufcs-polymorphic-paths.rs | 1 - src/test/run-pass/ufcs-trait-object.rs | 1 - src/test/run-pass/unboxed-closures-all-traits.rs | 1 - src/test/run-pass/unboxed-closures-blanket-fn-mut.rs | 1 - src/test/run-pass/unboxed-closures-blanket-fn.rs | 1 - src/test/run-pass/unboxed-closures-by-ref.rs | 1 - src/test/run-pass/unboxed-closures-call-fn-autoderef.rs | 1 - src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs | 1 - src/test/run-pass/unboxed-closures-counter-not-moved.rs | 1 - src/test/run-pass/unboxed-closures-cross-crate.rs | 1 - src/test/run-pass/unboxed-closures-drop.rs | 1 - src/test/run-pass/unboxed-closures-extern-fn-hr.rs | 1 - src/test/run-pass/unboxed-closures-extern-fn.rs | 1 - src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs | 1 - src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs | 1 - src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs | 1 - src/test/run-pass/unboxed-closures-infer-fnmut-move.rs | 1 - src/test/run-pass/unboxed-closures-infer-fnmut.rs | 1 - src/test/run-pass/unboxed-closures-infer-fnonce-move.rs | 1 - src/test/run-pass/unboxed-closures-infer-fnonce.rs | 1 - src/test/run-pass/unboxed-closures-infer-kind.rs | 1 - src/test/run-pass/unboxed-closures-infer-recursive-fn.rs | 1 - src/test/run-pass/unboxed-closures-infer-upvar.rs | 1 - src/test/run-pass/unboxed-closures-manual-impl.rs | 1 - .../unboxed-closures-move-some-upvars-in-by-ref-closure.rs | 1 - src/test/run-pass/unboxed-closures-simple.rs | 1 - src/test/run-pass/unboxed-closures-single-word-env.rs | 1 - src/test/run-pass/unboxed-closures-sugar-object.rs | 1 - src/test/run-pass/unboxed-closures-unique-type-id.rs | 1 - src/test/run-pass/unfold-cross-crate.rs | 1 - src/test/run-pass/uniq-self-in-mut-slot.rs | 1 - src/test/run-pass/unique-assign-copy.rs | 1 - src/test/run-pass/unique-assign-drop.rs | 1 - src/test/run-pass/unique-assign-generic.rs | 1 - src/test/run-pass/unique-assign.rs | 1 - src/test/run-pass/unique-autoderef-field.rs | 1 - src/test/run-pass/unique-autoderef-index.rs | 1 - src/test/run-pass/unique-cmp.rs | 1 - src/test/run-pass/unique-decl-init-copy.rs | 1 - src/test/run-pass/unique-decl-init.rs | 1 - src/test/run-pass/unique-decl-move.rs | 1 - src/test/run-pass/unique-decl.rs | 1 - src/test/run-pass/unique-deref.rs | 1 - src/test/run-pass/unique-destructure.rs | 1 - src/test/run-pass/unique-fn-arg-move.rs | 1 - src/test/run-pass/unique-fn-arg-mut.rs | 1 - src/test/run-pass/unique-fn-arg.rs | 1 - src/test/run-pass/unique-fn-ret.rs | 1 - src/test/run-pass/unique-in-vec-copy.rs | 1 - src/test/run-pass/unique-in-vec.rs | 1 - src/test/run-pass/unique-kinds.rs | 1 - src/test/run-pass/unique-move-drop.rs | 1 - src/test/run-pass/unique-move-temp.rs | 1 - src/test/run-pass/unique-move.rs | 1 - src/test/run-pass/unique-mutable.rs | 1 - src/test/run-pass/unique-pat-2.rs | 1 - src/test/run-pass/unique-pat.rs | 1 - src/test/run-pass/unique-rec.rs | 1 - src/test/run-pass/unique-send-2.rs | 1 - src/test/run-pass/unique-send.rs | 1 - src/test/run-pass/unique-swap.rs | 1 - src/test/run-pass/unit-like-struct-drop-run.rs | 1 - src/test/run-pass/unreachable-code-1.rs | 1 - src/test/run-pass/unreachable-code.rs | 1 - src/test/run-pass/unsafe-coercion.rs | 1 - src/test/run-pass/unsafe-pointer-assignability.rs | 1 - src/test/run-pass/unsized3.rs | 1 - src/test/run-pass/unwind-unique.rs | 1 - src/test/run-pass/variance-intersection-of-ref-and-opt-ref.rs | 1 - src/test/run-pass/variance-vec-covariant.rs | 1 - src/test/run-pass/vec-dst.rs | 1 - src/test/run-pass/vec-fixed-length.rs | 1 - src/test/run-pass/vec-growth.rs | 1 - src/test/run-pass/vec-macro-repeat.rs | 1 - src/test/run-pass/vec-macro-rvalue-scope.rs | 1 - src/test/run-pass/vec-macro-with-trailing-comma.rs | 1 - src/test/run-pass/vec-matching-autoslice.rs | 1 - src/test/run-pass/vec-matching-fixed.rs | 1 - src/test/run-pass/vec-matching-fold.rs | 1 - src/test/run-pass/vec-matching.rs | 1 - src/test/run-pass/vec-slice-drop.rs | 1 - src/test/run-pass/vec-slice.rs | 1 - src/test/run-pass/vec-tail-matching.rs | 1 - src/test/run-pass/vec-to_str.rs | 1 - src/test/run-pass/vec.rs | 1 - src/test/run-pass/vector-sort-panic-safe.rs | 1 - src/test/run-pass/wait-forked-but-failed-child.rs | 1 - src/test/run-pass/where-for-self.rs | 1 - src/test/run-pass/while-label.rs | 1 - src/test/run-pass/while-let.rs | 1 - src/test/run-pass/writealias.rs | 1 - src/test/run-pass/xcrate-address-insignificant.rs | 1 - src/test/run-pass/zero-size-type-destructors.rs | 1 - src/test/run-pass/zero_sized_subslice_match.rs | 1 - 792 files changed, 792 deletions(-) diff --git a/src/test/run-pass-fulldeps/rename-directory.rs b/src/test/run-pass-fulldeps/rename-directory.rs index a1e016bf2eaba..a0644e513a6e9 100644 --- a/src/test/run-pass-fulldeps/rename-directory.rs +++ b/src/test/run-pass-fulldeps/rename-directory.rs @@ -12,7 +12,6 @@ // because it needs TempDir, which is in extra // ignore-android -// pretty-expanded FIXME #23616 #![feature(rustc_private, path_ext)] diff --git a/src/test/run-pass/argument-passing.rs b/src/test/run-pass/argument-passing.rs index 7101cfb557967..d2a595804a4b2 100644 --- a/src/test/run-pass/argument-passing.rs +++ b/src/test/run-pass/argument-passing.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 struct X { x: isize diff --git a/src/test/run-pass/arith-2.rs b/src/test/run-pass/arith-2.rs index 0f4523c681884..c93049b87a764 100644 --- a/src/test/run-pass/arith-2.rs +++ b/src/test/run-pass/arith-2.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let i32_c: isize = 0x10101010; diff --git a/src/test/run-pass/arith-unsigned.rs b/src/test/run-pass/arith-unsigned.rs index 8a0fc8adc1895..e5ff97e3cdbd2 100644 --- a/src/test/run-pass/arith-unsigned.rs +++ b/src/test/run-pass/arith-unsigned.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(type_limits)] diff --git a/src/test/run-pass/artificial-block.rs b/src/test/run-pass/artificial-block.rs index 3348a6754ee82..53eec3c28c0de 100644 --- a/src/test/run-pass/artificial-block.rs +++ b/src/test/run-pass/artificial-block.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn f() -> isize { { return 3; } } diff --git a/src/test/run-pass/as-precedence.rs b/src/test/run-pass/as-precedence.rs index 8e38128975bb9..d89607077dcbe 100644 --- a/src/test/run-pass/as-precedence.rs +++ b/src/test/run-pass/as-precedence.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { assert_eq!(3 as usize * 3, 9); diff --git a/src/test/run-pass/asm-in-out-operand.rs b/src/test/run-pass/asm-in-out-operand.rs index 32924bcf74451..3eebc7acb0fd5 100644 --- a/src/test/run-pass/asm-in-out-operand.rs +++ b/src/test/run-pass/asm-in-out-operand.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(asm)] diff --git a/src/test/run-pass/asm-out-assign.rs b/src/test/run-pass/asm-out-assign.rs index 3cb7f6400daf4..d7913b473f85a 100644 --- a/src/test/run-pass/asm-out-assign.rs +++ b/src/test/run-pass/asm-out-assign.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(asm)] diff --git a/src/test/run-pass/assign-assign.rs b/src/test/run-pass/assign-assign.rs index 110f4720ceb68..186f91da07ccb 100644 --- a/src/test/run-pass/assign-assign.rs +++ b/src/test/run-pass/assign-assign.rs @@ -9,7 +9,6 @@ // except according to those terms. // Issue 483 - Assignment expressions result in nil -// pretty-expanded FIXME #23616 fn test_assign() { let mut x: isize; diff --git a/src/test/run-pass/assignability-trait.rs b/src/test/run-pass/assignability-trait.rs index 473f744a3ff61..f05a1520b8ef8 100644 --- a/src/test/run-pass/assignability-trait.rs +++ b/src/test/run-pass/assignability-trait.rs @@ -12,7 +12,6 @@ // making method calls, but only if there aren't any matches without // it. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/associated-types-basic.rs b/src/test/run-pass/associated-types-basic.rs index d4ed2ee2d6e55..06521e0ec78e8 100644 --- a/src/test/run-pass/associated-types-basic.rs +++ b/src/test/run-pass/associated-types-basic.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/associated-types-binding-in-trait.rs b/src/test/run-pass/associated-types-binding-in-trait.rs index 39fc224148e8e..d82ba6add75c7 100644 --- a/src/test/run-pass/associated-types-binding-in-trait.rs +++ b/src/test/run-pass/associated-types-binding-in-trait.rs @@ -11,7 +11,6 @@ // Test a case where the associated type binding (to `bool`, in this // case) is derived from the trait definition. Issue #21636. -// pretty-expanded FIXME #23616 use std::vec; diff --git a/src/test/run-pass/associated-types-bound.rs b/src/test/run-pass/associated-types-bound.rs index 2301821f66358..4eacd120bc690 100644 --- a/src/test/run-pass/associated-types-bound.rs +++ b/src/test/run-pass/associated-types-bound.rs @@ -10,7 +10,6 @@ // Test equality constrai32s on associated types in a where clause. -// pretty-expanded FIXME #23616 pub trait ToI32 { fn to_i32(&self) -> i32; diff --git a/src/test/run-pass/associated-types-constant-type.rs b/src/test/run-pass/associated-types-constant-type.rs index 5729fab475b78..77ab616ca918b 100644 --- a/src/test/run-pass/associated-types-constant-type.rs +++ b/src/test/run-pass/associated-types-constant-type.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait SignedUnsigned { type Opposite; diff --git a/src/test/run-pass/associated-types-doubleendediterator-object.rs b/src/test/run-pass/associated-types-doubleendediterator-object.rs index 5dc289194ff3b..1661812520b3e 100644 --- a/src/test/run-pass/associated-types-doubleendediterator-object.rs +++ b/src/test/run-pass/associated-types-doubleendediterator-object.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/associated-types-enum-field-named.rs b/src/test/run-pass/associated-types-enum-field-named.rs index 8cf97fe62fea5..7014cc59b71db 100644 --- a/src/test/run-pass/associated-types-enum-field-named.rs +++ b/src/test/run-pass/associated-types-enum-field-named.rs @@ -10,7 +10,6 @@ // Test associated types appearing in struct-like enum variants. -// pretty-expanded FIXME #23616 use self::VarValue::*; diff --git a/src/test/run-pass/associated-types-enum-field-numbered.rs b/src/test/run-pass/associated-types-enum-field-numbered.rs index 3c57da6b4a3eb..c983fdefc0e35 100644 --- a/src/test/run-pass/associated-types-enum-field-numbered.rs +++ b/src/test/run-pass/associated-types-enum-field-numbered.rs @@ -10,7 +10,6 @@ // Test associated types appearing in tuple-like enum variants. -// pretty-expanded FIXME #23616 use self::VarValue::*; diff --git a/src/test/run-pass/associated-types-in-default-method.rs b/src/test/run-pass/associated-types-in-default-method.rs index 2a1b9bdd2faf6..74199f57fb634 100644 --- a/src/test/run-pass/associated-types-in-default-method.rs +++ b/src/test/run-pass/associated-types-in-default-method.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Get { type Value; diff --git a/src/test/run-pass/associated-types-in-fn.rs b/src/test/run-pass/associated-types-in-fn.rs index 40b10fbfcaca6..dcd7895fa99e6 100644 --- a/src/test/run-pass/associated-types-in-fn.rs +++ b/src/test/run-pass/associated-types-in-fn.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Get { type Value; diff --git a/src/test/run-pass/associated-types-in-impl-generics.rs b/src/test/run-pass/associated-types-in-impl-generics.rs index 99a9b7c23febd..5b81ac7090876 100644 --- a/src/test/run-pass/associated-types-in-impl-generics.rs +++ b/src/test/run-pass/associated-types-in-impl-generics.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Get { type Value; diff --git a/src/test/run-pass/associated-types-in-inherent-method.rs b/src/test/run-pass/associated-types-in-inherent-method.rs index 0012d9d759632..5eaf4c2bc8396 100644 --- a/src/test/run-pass/associated-types-in-inherent-method.rs +++ b/src/test/run-pass/associated-types-in-inherent-method.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Get { type Value; diff --git a/src/test/run-pass/associated-types-issue-20220.rs b/src/test/run-pass/associated-types-issue-20220.rs index 718ea542799bb..31336787e4c13 100644 --- a/src/test/run-pass/associated-types-issue-20220.rs +++ b/src/test/run-pass/associated-types-issue-20220.rs @@ -10,7 +10,6 @@ // Test references to `Self::Item` in the trait. Issue #20220. -// pretty-expanded FIXME #23616 use std::vec; diff --git a/src/test/run-pass/associated-types-issue-21212.rs b/src/test/run-pass/associated-types-issue-21212.rs index 057677a008785..cf4b82721112c 100644 --- a/src/test/run-pass/associated-types-issue-21212.rs +++ b/src/test/run-pass/associated-types-issue-21212.rs @@ -13,7 +13,6 @@ // where clauses in the environment which in turn required normalizing // `Self::Input`. -// pretty-expanded FIXME #23616 pub trait Parser { type Input; diff --git a/src/test/run-pass/associated-types-iterator-binding.rs b/src/test/run-pass/associated-types-iterator-binding.rs index 24c5a3e9a8375..181ce52eb4baf 100644 --- a/src/test/run-pass/associated-types-iterator-binding.rs +++ b/src/test/run-pass/associated-types-iterator-binding.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn pairwise_sub>(mut t: T) -> isize { let mut result = 0; diff --git a/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs b/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs index 151a9da948e83..dfd468884a167 100644 --- a/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs +++ b/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs @@ -12,7 +12,6 @@ // `Item` originates in a where-clause, not the declaration of // `T`. Issue #20300. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/associated-types-projection-from-known-type-in-impl.rs b/src/test/run-pass/associated-types-projection-from-known-type-in-impl.rs index 2518ccf1cb474..8054b3aa52a1d 100644 --- a/src/test/run-pass/associated-types-projection-from-known-type-in-impl.rs +++ b/src/test/run-pass/associated-types-projection-from-known-type-in-impl.rs @@ -10,7 +10,6 @@ // Test where the impl self type uses a projection from a constant type. -// pretty-expanded FIXME #23616 trait Int { diff --git a/src/test/run-pass/associated-types-projection-in-supertrait.rs b/src/test/run-pass/associated-types-projection-in-supertrait.rs index dbc2164c93a69..70c7602ffceb1 100644 --- a/src/test/run-pass/associated-types-projection-in-supertrait.rs +++ b/src/test/run-pass/associated-types-projection-in-supertrait.rs @@ -11,7 +11,6 @@ // Test that we are handle to correctly handle a projection type // that appears in a supertrait bound. Issue #20559. -// pretty-expanded FIXME #23616 trait A { diff --git a/src/test/run-pass/associated-types-ref-in-struct-literal.rs b/src/test/run-pass/associated-types-ref-in-struct-literal.rs index 945340008d876..3b7fb65a8b4aa 100644 --- a/src/test/run-pass/associated-types-ref-in-struct-literal.rs +++ b/src/test/run-pass/associated-types-ref-in-struct-literal.rs @@ -10,7 +10,6 @@ // Test associated type references in a struct literal. Issue #20535. -// pretty-expanded FIXME #23616 pub trait Foo { type Bar; diff --git a/src/test/run-pass/associated-types-return.rs b/src/test/run-pass/associated-types-return.rs index f190e81d8a6ad..5bba54e57b477 100644 --- a/src/test/run-pass/associated-types-return.rs +++ b/src/test/run-pass/associated-types-return.rs @@ -10,7 +10,6 @@ // Test equality constraints on associated types in a where clause. -// pretty-expanded FIXME #23616 pub trait Foo { type A; diff --git a/src/test/run-pass/associated-types-simple.rs b/src/test/run-pass/associated-types-simple.rs index 5a2761365bf30..776b2183d3908 100644 --- a/src/test/run-pass/associated-types-simple.rs +++ b/src/test/run-pass/associated-types-simple.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Get { type Value; diff --git a/src/test/run-pass/associated-types-stream.rs b/src/test/run-pass/associated-types-stream.rs index a2b7cf2106eb7..6adfaabcc23b4 100644 --- a/src/test/run-pass/associated-types-stream.rs +++ b/src/test/run-pass/associated-types-stream.rs @@ -11,7 +11,6 @@ // Test references to the trait `Stream` in the bounds for associated // types defined on `Stream`. Issue #20551. -// pretty-expanded FIXME #23616 trait Stream { type Car; diff --git a/src/test/run-pass/associated-types-struct-field-named.rs b/src/test/run-pass/associated-types-struct-field-named.rs index d1872e4fb55f4..00746c32e1c31 100644 --- a/src/test/run-pass/associated-types-struct-field-named.rs +++ b/src/test/run-pass/associated-types-struct-field-named.rs @@ -11,7 +11,6 @@ // Test that we correctly normalize the type of a struct field // which has an associated type. -// pretty-expanded FIXME #23616 pub trait UnifyKey { type Value; diff --git a/src/test/run-pass/associated-types-struct-field-numbered.rs b/src/test/run-pass/associated-types-struct-field-numbered.rs index 3d97c503dca5f..25e89892a29af 100644 --- a/src/test/run-pass/associated-types-struct-field-numbered.rs +++ b/src/test/run-pass/associated-types-struct-field-numbered.rs @@ -11,7 +11,6 @@ // Test that we correctly normalize the type of a struct field // which has an associated type. -// pretty-expanded FIXME #23616 pub trait UnifyKey { type Value; diff --git a/src/test/run-pass/associated-types-sugar-path.rs b/src/test/run-pass/associated-types-sugar-path.rs index 353b49b49cedf..1432369f7143d 100644 --- a/src/test/run-pass/associated-types-sugar-path.rs +++ b/src/test/run-pass/associated-types-sugar-path.rs @@ -10,7 +10,6 @@ // Test paths to associated types using the type-parameter-only sugar. -// pretty-expanded FIXME #23616 pub trait Foo { type A; diff --git a/src/test/run-pass/attr-main-2.rs b/src/test/run-pass/attr-main-2.rs index 4680f47fad6ce..b3c9ea541b712 100644 --- a/src/test/run-pass/attr-main-2.rs +++ b/src/test/run-pass/attr-main-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(main)] diff --git a/src/test/run-pass/attr-no-drop-flag-size.rs b/src/test/run-pass/attr-no-drop-flag-size.rs index af8e4b7d4a1a7..893fb85b529a7 100644 --- a/src/test/run-pass/attr-no-drop-flag-size.rs +++ b/src/test/run-pass/attr-no-drop-flag-size.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] #![feature(unsafe_no_drop_flag)] diff --git a/src/test/run-pass/auto-loop.rs b/src/test/run-pass/auto-loop.rs index 2e79183755a18..babc0db4c3190 100644 --- a/src/test/run-pass/auto-loop.rs +++ b/src/test/run-pass/auto-loop.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let mut sum = 0; diff --git a/src/test/run-pass/auto-ref-sliceable.rs b/src/test/run-pass/auto-ref-sliceable.rs index 6dab0e5197138..5b12edb427562 100644 --- a/src/test/run-pass/auto-ref-sliceable.rs +++ b/src/test/run-pass/auto-ref-sliceable.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait Pushable { fn push_val(&mut self, t: T); diff --git a/src/test/run-pass/autobind.rs b/src/test/run-pass/autobind.rs index 7d30b549ebea4..1f3d17ad55c08 100644 --- a/src/test/run-pass/autobind.rs +++ b/src/test/run-pass/autobind.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn f(x: Vec) -> T { return x.into_iter().next().unwrap(); } diff --git a/src/test/run-pass/autoderef-method-on-trait.rs b/src/test/run-pass/autoderef-method-on-trait.rs index d7eee85f50273..582fd020dd061 100644 --- a/src/test/run-pass/autoderef-method-on-trait.rs +++ b/src/test/run-pass/autoderef-method-on-trait.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/autoderef-method-priority.rs b/src/test/run-pass/autoderef-method-priority.rs index 6c52035b708de..c80a92a185a2e 100644 --- a/src/test/run-pass/autoderef-method-priority.rs +++ b/src/test/run-pass/autoderef-method-priority.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/autoderef-method-twice-but-not-thrice.rs b/src/test/run-pass/autoderef-method-twice-but-not-thrice.rs index 809ab0a3521dd..2a782cfa176ee 100644 --- a/src/test/run-pass/autoderef-method-twice-but-not-thrice.rs +++ b/src/test/run-pass/autoderef-method-twice-but-not-thrice.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/autoderef-method-twice.rs b/src/test/run-pass/autoderef-method-twice.rs index 9c7828c893895..a1bcf65ab75fa 100644 --- a/src/test/run-pass/autoderef-method-twice.rs +++ b/src/test/run-pass/autoderef-method-twice.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/autoderef-method.rs b/src/test/run-pass/autoderef-method.rs index e63dd07eb0752..326218674ae3f 100644 --- a/src/test/run-pass/autoderef-method.rs +++ b/src/test/run-pass/autoderef-method.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/autoref-intermediate-types-issue-3585.rs b/src/test/run-pass/autoref-intermediate-types-issue-3585.rs index 0f935776fc554..05f12fd089ad4 100644 --- a/src/test/run-pass/autoref-intermediate-types-issue-3585.rs +++ b/src/test/run-pass/autoref-intermediate-types-issue-3585.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/big-literals.rs b/src/test/run-pass/big-literals.rs index ab9d892ce2b60..19c0e7baaa0a1 100644 --- a/src/test/run-pass/big-literals.rs +++ b/src/test/run-pass/big-literals.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/binary-minus-without-space.rs b/src/test/run-pass/binary-minus-without-space.rs index 1fe9dde844a4f..01a9ec8093973 100644 --- a/src/test/run-pass/binary-minus-without-space.rs +++ b/src/test/run-pass/binary-minus-without-space.rs @@ -10,7 +10,6 @@ // Check that issue #954 stays fixed -// pretty-expanded FIXME #23616 pub fn main() { match -1 { -1 => {}, _ => panic!("wat") } diff --git a/src/test/run-pass/bind-by-move.rs b/src/test/run-pass/bind-by-move.rs index 5a6e801501fcf..9be7d63ab951d 100644 --- a/src/test/run-pass/bind-by-move.rs +++ b/src/test/run-pass/bind-by-move.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::sync::Arc; fn dispose(_x: Arc) { } diff --git a/src/test/run-pass/bind-field-short-with-modifiers.rs b/src/test/run-pass/bind-field-short-with-modifiers.rs index e61ff61a21622..b4c38bf450b1b 100644 --- a/src/test/run-pass/bind-field-short-with-modifiers.rs +++ b/src/test/run-pass/bind-field-short-with-modifiers.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { struct Foo { x: isize, y: isize } diff --git a/src/test/run-pass/block-arg-call-as.rs b/src/test/run-pass/block-arg-call-as.rs index 5944438e20d9a..73cba2e4e0a7c 100644 --- a/src/test/run-pass/block-arg-call-as.rs +++ b/src/test/run-pass/block-arg-call-as.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn asBlock(f: F) -> usize where F: FnOnce() -> usize { return f(); diff --git a/src/test/run-pass/block-expr-precedence.rs b/src/test/run-pass/block-expr-precedence.rs index 01bd8ce10cd09..ac8f501257361 100644 --- a/src/test/run-pass/block-expr-precedence.rs +++ b/src/test/run-pass/block-expr-precedence.rs @@ -13,7 +13,6 @@ // no-reformat -// pretty-expanded FIXME #23616 /* * diff --git a/src/test/run-pass/block-fn-coerce.rs b/src/test/run-pass/block-fn-coerce.rs index 0addd33c1e4a3..3e6109da39a26 100644 --- a/src/test/run-pass/block-fn-coerce.rs +++ b/src/test/run-pass/block-fn-coerce.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn force(f: F) -> isize where F: FnOnce() -> isize { return f(); } diff --git a/src/test/run-pass/bool-not.rs b/src/test/run-pass/bool-not.rs index c46684af6efda..fa0b86d0a0246 100644 --- a/src/test/run-pass/bool-not.rs +++ b/src/test/run-pass/bool-not.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { if !false { assert!((true)); } else { assert!((false)); } diff --git a/src/test/run-pass/bool.rs b/src/test/run-pass/bool.rs index a2b19d32054a5..53b568b06b5b6 100644 --- a/src/test/run-pass/bool.rs +++ b/src/test/run-pass/bool.rs @@ -10,7 +10,6 @@ // Basic boolean tests -// pretty-expanded FIXME #23616 use std::cmp::Ordering::{Equal, Greater, Less}; use std::ops::{BitAnd, BitOr, BitXor}; diff --git a/src/test/run-pass/borrow-tuple-fields.rs b/src/test/run-pass/borrow-tuple-fields.rs index 7cf61bd569dfb..f0d09688192c6 100644 --- a/src/test/run-pass/borrow-tuple-fields.rs +++ b/src/test/run-pass/borrow-tuple-fields.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Foo(isize, isize); diff --git a/src/test/run-pass/borrowck-borrow-from-expr-block.rs b/src/test/run-pass/borrowck-borrow-from-expr-block.rs index 24c7285b1fb6f..7fdc65a96e238 100644 --- a/src/test/run-pass/borrowck-borrow-from-expr-block.rs +++ b/src/test/run-pass/borrowck-borrow-from-expr-block.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/borrowck-closures-two-imm.rs b/src/test/run-pass/borrowck-closures-two-imm.rs index 6ccb2203bca8e..5b15c8f0797fa 100644 --- a/src/test/run-pass/borrowck-closures-two-imm.rs +++ b/src/test/run-pass/borrowck-closures-two-imm.rs @@ -14,7 +14,6 @@ // that the main function can read the variable too while // the closures are in scope. Issue #6801. -// pretty-expanded FIXME #23616 fn a() -> i32 { let mut x = 3; diff --git a/src/test/run-pass/borrowck-fixed-length-vecs.rs b/src/test/run-pass/borrowck-fixed-length-vecs.rs index 3f38a8df04c57..0e33351894d14 100644 --- a/src/test/run-pass/borrowck-fixed-length-vecs.rs +++ b/src/test/run-pass/borrowck-fixed-length-vecs.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = [22]; diff --git a/src/test/run-pass/borrowck-freeze-frozen-mut.rs b/src/test/run-pass/borrowck-freeze-frozen-mut.rs index eaa78553d85c5..380bd398a7cb2 100644 --- a/src/test/run-pass/borrowck-freeze-frozen-mut.rs +++ b/src/test/run-pass/borrowck-freeze-frozen-mut.rs @@ -10,7 +10,6 @@ // Test that a `&mut` inside of an `&` is freezable. -// pretty-expanded FIXME #23616 struct MutSlice<'a, T:'a> { data: &'a mut [T] diff --git a/src/test/run-pass/borrowck-macro-interaction-issue-6304.rs b/src/test/run-pass/borrowck-macro-interaction-issue-6304.rs index b40504f37d4d9..fb30c85e70963 100644 --- a/src/test/run-pass/borrowck-macro-interaction-issue-6304.rs +++ b/src/test/run-pass/borrowck-macro-interaction-issue-6304.rs @@ -11,7 +11,6 @@ // Check that we do not ICE when compiling this // macro, which reuses the expression `$id` -// pretty-expanded FIXME #23616 #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/test/run-pass/borrowck-move-by-capture-ok.rs b/src/test/run-pass/borrowck-move-by-capture-ok.rs index 7c03c6a9a489c..bbc668f5cabfe 100644 --- a/src/test/run-pass/borrowck-move-by-capture-ok.rs +++ b/src/test/run-pass/borrowck-move-by-capture-ok.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs b/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs index 4d37bcb5a4896..d55517c65d667 100644 --- a/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs +++ b/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn want_slice(v: &[isize]) -> isize { let mut sum = 0; diff --git a/src/test/run-pass/borrowck-pat-reassign-no-binding.rs b/src/test/run-pass/borrowck-pat-reassign-no-binding.rs index c3b69333dc555..e0a5db678d2f4 100644 --- a/src/test/run-pass/borrowck-pat-reassign-no-binding.rs +++ b/src/test/run-pass/borrowck-pat-reassign-no-binding.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let mut x = None; diff --git a/src/test/run-pass/borrowck-rvalues-mutable.rs b/src/test/run-pass/borrowck-rvalues-mutable.rs index 1b20f6c706162..045e8d952adaa 100644 --- a/src/test/run-pass/borrowck-rvalues-mutable.rs +++ b/src/test/run-pass/borrowck-rvalues-mutable.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Counter { value: usize diff --git a/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs b/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs index 36a84a62d48fb..59a5fea769a6f 100644 --- a/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs +++ b/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs @@ -12,7 +12,6 @@ // limited to the deref operation itself, and does not infect the // block as a whole. -// pretty-expanded FIXME #23616 struct Box { x: usize diff --git a/src/test/run-pass/borrowck-univariant-enum.rs b/src/test/run-pass/borrowck-univariant-enum.rs index a5c68c5ecf976..2e8ddb0806472 100644 --- a/src/test/run-pass/borrowck-univariant-enum.rs +++ b/src/test/run-pass/borrowck-univariant-enum.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 use std::cell::Cell; diff --git a/src/test/run-pass/borrowed-ptr-pattern-2.rs b/src/test/run-pass/borrowed-ptr-pattern-2.rs index aaf962577ff24..3e47764ba0264 100644 --- a/src/test/run-pass/borrowed-ptr-pattern-2.rs +++ b/src/test/run-pass/borrowed-ptr-pattern-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn foo(s: &String) -> bool { match &**s { diff --git a/src/test/run-pass/borrowed-ptr-pattern-3.rs b/src/test/run-pass/borrowed-ptr-pattern-3.rs index c8cc29b9bdacb..91228efb9c1cb 100644 --- a/src/test/run-pass/borrowed-ptr-pattern-3.rs +++ b/src/test/run-pass/borrowed-ptr-pattern-3.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn foo<'r>(s: &'r usize) -> bool { match s { diff --git a/src/test/run-pass/borrowed-ptr-pattern-infallible.rs b/src/test/run-pass/borrowed-ptr-pattern-infallible.rs index 69cb27dcf899e..6656eb41f2e3a 100644 --- a/src/test/run-pass/borrowed-ptr-pattern-infallible.rs +++ b/src/test/run-pass/borrowed-ptr-pattern-infallible.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let (&x, &y) = (&3, &'a'); diff --git a/src/test/run-pass/borrowed-ptr-pattern-option.rs b/src/test/run-pass/borrowed-ptr-pattern-option.rs index 14b6c32a11e51..e1e9381eeb8e7 100644 --- a/src/test/run-pass/borrowed-ptr-pattern-option.rs +++ b/src/test/run-pass/borrowed-ptr-pattern-option.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn select<'r>(x: &'r Option, y: &'r Option) -> &'r Option { match (x, y) { diff --git a/src/test/run-pass/borrowed-ptr-pattern.rs b/src/test/run-pass/borrowed-ptr-pattern.rs index 52322c41236b8..3042ff7743b70 100644 --- a/src/test/run-pass/borrowed-ptr-pattern.rs +++ b/src/test/run-pass/borrowed-ptr-pattern.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn foo(x: &T) -> T{ match x { diff --git a/src/test/run-pass/break.rs b/src/test/run-pass/break.rs index 80934c48515dc..ea136e2dc4854 100644 --- a/src/test/run-pass/break.rs +++ b/src/test/run-pass/break.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let mut i = 0; diff --git a/src/test/run-pass/bug-7183-generics.rs b/src/test/run-pass/bug-7183-generics.rs index 5467ed10e98ea..80fd09114fc95 100644 --- a/src/test/run-pass/bug-7183-generics.rs +++ b/src/test/run-pass/bug-7183-generics.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Speak : Sized { fn say(&self, s:&str) -> String; diff --git a/src/test/run-pass/builtin-superkinds-capabilities-transitive.rs b/src/test/run-pass/builtin-superkinds-capabilities-transitive.rs index eb6d1028331be..c5064d56ca123 100644 --- a/src/test/run-pass/builtin-superkinds-capabilities-transitive.rs +++ b/src/test/run-pass/builtin-superkinds-capabilities-transitive.rs @@ -14,7 +14,6 @@ // a Send. Basically this just makes sure rustc is using // each_bound_trait_and_supertraits in type_contents correctly. -// pretty-expanded FIXME #23616 use std::sync::mpsc::{channel, Sender}; diff --git a/src/test/run-pass/builtin-superkinds-capabilities-xc.rs b/src/test/run-pass/builtin-superkinds-capabilities-xc.rs index 082f5944fd3da..183e6fe232cd3 100644 --- a/src/test/run-pass/builtin-superkinds-capabilities-xc.rs +++ b/src/test/run-pass/builtin-superkinds-capabilities-xc.rs @@ -14,7 +14,6 @@ // Tests "capabilities" granted by traits with super-builtin-kinds, // even when using them cross-crate. -// pretty-expanded FIXME #23616 extern crate trait_superkinds_in_metadata; diff --git a/src/test/run-pass/builtin-superkinds-capabilities.rs b/src/test/run-pass/builtin-superkinds-capabilities.rs index 594fb5ec70780..a4d5c943b1f68 100644 --- a/src/test/run-pass/builtin-superkinds-capabilities.rs +++ b/src/test/run-pass/builtin-superkinds-capabilities.rs @@ -12,7 +12,6 @@ // builtin-kinds, e.g., if a trait requires Send to implement, then // at usage site of that trait, we know we have the Send capability. -// pretty-expanded FIXME #23616 use std::sync::mpsc::{channel, Sender, Receiver}; diff --git a/src/test/run-pass/builtin-superkinds-self-type.rs b/src/test/run-pass/builtin-superkinds-self-type.rs index 924a8c023f8b6..c4dc7d78b06d5 100644 --- a/src/test/run-pass/builtin-superkinds-self-type.rs +++ b/src/test/run-pass/builtin-superkinds-self-type.rs @@ -11,7 +11,6 @@ // Tests the ability for the Self type in default methods to use // capabilities granted by builtin kinds as supertraits. -// pretty-expanded FIXME #23616 use std::sync::mpsc::{Sender, channel}; diff --git a/src/test/run-pass/by-value-self-in-mut-slot.rs b/src/test/run-pass/by-value-self-in-mut-slot.rs index 464c24fc8b032..5bbdec95b1576 100644 --- a/src/test/run-pass/by-value-self-in-mut-slot.rs +++ b/src/test/run-pass/by-value-self-in-mut-slot.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct X { a: isize diff --git a/src/test/run-pass/call-closure-from-overloaded-op.rs b/src/test/run-pass/call-closure-from-overloaded-op.rs index e3ee282ec2a4e..e35398a22917f 100644 --- a/src/test/run-pass/call-closure-from-overloaded-op.rs +++ b/src/test/run-pass/call-closure-from-overloaded-op.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn foo() -> isize { 22 } diff --git a/src/test/run-pass/capture-clauses-boxed-closures.rs b/src/test/run-pass/capture-clauses-boxed-closures.rs index 5bf6f5fb04891..45cec79e1a30e 100644 --- a/src/test/run-pass/capture-clauses-boxed-closures.rs +++ b/src/test/run-pass/capture-clauses-boxed-closures.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn each(x: &[T], mut f: F) where F: FnMut(&T) { for val in x { diff --git a/src/test/run-pass/capture-clauses-unboxed-closures.rs b/src/test/run-pass/capture-clauses-unboxed-closures.rs index 448ed76fe96b9..5e7d5aacb8d0d 100644 --- a/src/test/run-pass/capture-clauses-unboxed-closures.rs +++ b/src/test/run-pass/capture-clauses-unboxed-closures.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/cast.rs b/src/test/run-pass/cast.rs index 03a73555f856a..bb60626a4bf02 100644 --- a/src/test/run-pass/cast.rs +++ b/src/test/run-pass/cast.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let i: isize = 'Q' as isize; diff --git a/src/test/run-pass/cci_nested_exe.rs b/src/test/run-pass/cci_nested_exe.rs index 665469883043c..e4f4a4f3a576c 100644 --- a/src/test/run-pass/cci_nested_exe.rs +++ b/src/test/run-pass/cci_nested_exe.rs @@ -10,7 +10,6 @@ // aux-build:cci_nested_lib.rs -// pretty-expanded FIXME #23616 #![feature(globs)] diff --git a/src/test/run-pass/cell-does-not-clone.rs b/src/test/run-pass/cell-does-not-clone.rs index c87a3e8bb93d6..c1fcf49654626 100644 --- a/src/test/run-pass/cell-does-not-clone.rs +++ b/src/test/run-pass/cell-does-not-clone.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::cell::Cell; diff --git a/src/test/run-pass/cfg-macros-foo.rs b/src/test/run-pass/cfg-macros-foo.rs index 5fa1bc47f877a..36b9ce1585cf8 100644 --- a/src/test/run-pass/cfg-macros-foo.rs +++ b/src/test/run-pass/cfg-macros-foo.rs @@ -13,7 +13,6 @@ // check that cfg correctly chooses between the macro impls (see also // cfg-macros-notfoo.rs) -// pretty-expanded FIXME #23616 #[cfg(foo)] #[macro_use] diff --git a/src/test/run-pass/cfg-macros-notfoo.rs b/src/test/run-pass/cfg-macros-notfoo.rs index 7cddac160319f..4e1b833add017 100644 --- a/src/test/run-pass/cfg-macros-notfoo.rs +++ b/src/test/run-pass/cfg-macros-notfoo.rs @@ -13,7 +13,6 @@ // check that cfg correctly chooses between the macro impls (see also // cfg-macros-foo.rs) -// pretty-expanded FIXME #23616 #[cfg(foo)] #[macro_use] diff --git a/src/test/run-pass/cfgs-on-items.rs b/src/test/run-pass/cfgs-on-items.rs index 5c22d5c869042..1b692d8bd51f4 100644 --- a/src/test/run-pass/cfgs-on-items.rs +++ b/src/test/run-pass/cfgs-on-items.rs @@ -11,7 +11,6 @@ // compile-flags: --cfg fooA --cfg fooB // fooA AND !bar -// pretty-expanded FIXME #23616 #[cfg(all(fooA, not(bar)))] fn foo1() -> isize { 1 } diff --git a/src/test/run-pass/char.rs b/src/test/run-pass/char.rs index 801b01918e103..d63512f8066cb 100644 --- a/src/test/run-pass/char.rs +++ b/src/test/run-pass/char.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let c: char = 'x'; diff --git a/src/test/run-pass/check-static-mut-slices.rs b/src/test/run-pass/check-static-mut-slices.rs index 19c3458ef7b28..5959dd4c389c8 100644 --- a/src/test/run-pass/check-static-mut-slices.rs +++ b/src/test/run-pass/check-static-mut-slices.rs @@ -10,7 +10,6 @@ // Checks that mutable static items can have mutable slices -// pretty-expanded FIXME #23616 static mut TEST: &'static mut [isize] = &mut [1]; diff --git a/src/test/run-pass/check-static-slice.rs b/src/test/run-pass/check-static-slice.rs index 8a7ae1de9bc70..8408597f35409 100644 --- a/src/test/run-pass/check-static-slice.rs +++ b/src/test/run-pass/check-static-slice.rs @@ -11,7 +11,6 @@ // Check that the various ways of getting to a reference to a vec (both sized // and unsized) work properly. -// pretty-expanded FIXME #23616 const aa: [isize; 3] = [1, 2, 3]; const ab: &'static [isize; 3] = &aa; diff --git a/src/test/run-pass/class-exports.rs b/src/test/run-pass/class-exports.rs index 675acf1dd62e0..6783609b256c9 100644 --- a/src/test/run-pass/class-exports.rs +++ b/src/test/run-pass/class-exports.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 /* Test that exporting a class also exports its public fields and methods */ diff --git a/src/test/run-pass/class-method-cross-crate.rs b/src/test/run-pass/class-method-cross-crate.rs index a5c60e3a7b53c..6ab158dc37ca5 100644 --- a/src/test/run-pass/class-method-cross-crate.rs +++ b/src/test/run-pass/class-method-cross-crate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:cci_class_2.rs -// pretty-expanded FIXME #23616 extern crate cci_class_2; use cci_class_2::kitties::cat; diff --git a/src/test/run-pass/class-methods-cross-crate.rs b/src/test/run-pass/class-methods-cross-crate.rs index 73abaf7d34bb8..666571007595c 100644 --- a/src/test/run-pass/class-methods-cross-crate.rs +++ b/src/test/run-pass/class-methods-cross-crate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:cci_class_3.rs -// pretty-expanded FIXME #23616 extern crate cci_class_3; use cci_class_3::kitties::cat; diff --git a/src/test/run-pass/class-methods.rs b/src/test/run-pass/class-methods.rs index d454bdd73a1ac..93af906bd5a6c 100644 --- a/src/test/run-pass/class-methods.rs +++ b/src/test/run-pass/class-methods.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct cat { meows : usize, diff --git a/src/test/run-pass/class-poly-methods-cross-crate.rs b/src/test/run-pass/class-poly-methods-cross-crate.rs index 6537a931fa615..4d247bde190de 100644 --- a/src/test/run-pass/class-poly-methods-cross-crate.rs +++ b/src/test/run-pass/class-poly-methods-cross-crate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:cci_class_6.rs -// pretty-expanded FIXME #23616 extern crate cci_class_6; use cci_class_6::kitties::cat; diff --git a/src/test/run-pass/class-poly-methods.rs b/src/test/run-pass/class-poly-methods.rs index 27f872d532c79..2528ff5128f9c 100644 --- a/src/test/run-pass/class-poly-methods.rs +++ b/src/test/run-pass/class-poly-methods.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 struct cat { info : Vec , diff --git a/src/test/run-pass/classes-cross-crate.rs b/src/test/run-pass/classes-cross-crate.rs index 36d7bd6b3ca48..3d99aa1ef1d08 100644 --- a/src/test/run-pass/classes-cross-crate.rs +++ b/src/test/run-pass/classes-cross-crate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:cci_class_4.rs -// pretty-expanded FIXME #23616 extern crate cci_class_4; use cci_class_4::kitties::cat; diff --git a/src/test/run-pass/classes-simple-cross-crate.rs b/src/test/run-pass/classes-simple-cross-crate.rs index cfa13dbe622f7..db15001c62f19 100644 --- a/src/test/run-pass/classes-simple-cross-crate.rs +++ b/src/test/run-pass/classes-simple-cross-crate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:cci_class.rs -// pretty-expanded FIXME #23616 extern crate cci_class; use cci_class::kitties::cat; diff --git a/src/test/run-pass/classes-simple-method.rs b/src/test/run-pass/classes-simple-method.rs index 0d9f859d2d14d..64ec2ea7e71ae 100644 --- a/src/test/run-pass/classes-simple-method.rs +++ b/src/test/run-pass/classes-simple-method.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct cat { meows : usize, diff --git a/src/test/run-pass/classes-simple.rs b/src/test/run-pass/classes-simple.rs index f520623a75ab5..c475fb2cff945 100644 --- a/src/test/run-pass/classes-simple.rs +++ b/src/test/run-pass/classes-simple.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct cat { meows : usize, diff --git a/src/test/run-pass/cleanup-rvalue-during-if-and-while.rs b/src/test/run-pass/cleanup-rvalue-during-if-and-while.rs index 1d0030fd3d362..d813a6d810236 100644 --- a/src/test/run-pass/cleanup-rvalue-during-if-and-while.rs +++ b/src/test/run-pass/cleanup-rvalue-during-if-and-while.rs @@ -12,7 +12,6 @@ // This test verifies that temporaries created for `while`'s and `if` // conditions are dropped after the condition is evaluated. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/cleanup-rvalue-temp-during-incomplete-alloc.rs b/src/test/run-pass/cleanup-rvalue-temp-during-incomplete-alloc.rs index 3b5421e5aff4c..344ea63c7c74d 100644 --- a/src/test/run-pass/cleanup-rvalue-temp-during-incomplete-alloc.rs +++ b/src/test/run-pass/cleanup-rvalue-temp-during-incomplete-alloc.rs @@ -24,7 +24,6 @@ // It's unclear how likely such a bug is to recur, but it seems like a // scenario worth testing. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/closure-inference.rs b/src/test/run-pass/closure-inference.rs index 06b6e1b5abedd..630a510ca651e 100644 --- a/src/test/run-pass/closure-inference.rs +++ b/src/test/run-pass/closure-inference.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn foo(i: isize) -> isize { i + 1 } diff --git a/src/test/run-pass/closure-inference2.rs b/src/test/run-pass/closure-inference2.rs index 328a27b3f1e8a..2f24cd4ce4043 100644 --- a/src/test/run-pass/closure-inference2.rs +++ b/src/test/run-pass/closure-inference2.rs @@ -10,7 +10,6 @@ // Test a rather underspecified example: -// pretty-expanded FIXME #23616 pub fn main() { let f = {|i| i}; diff --git a/src/test/run-pass/cmp-default.rs b/src/test/run-pass/cmp-default.rs index 2b7557c7bc563..cd3f556864e64 100644 --- a/src/test/run-pass/cmp-default.rs +++ b/src/test/run-pass/cmp-default.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::cmp::Ordering; diff --git a/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs b/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs index 6000b358acf26..5258ad1af5150 100644 --- a/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct SpeechMaker { speeches: usize diff --git a/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs index 2e41ff3a56041..4e116ae146691 100644 --- a/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn bar(v: &mut [usize]) -> Vec { v.to_vec() diff --git a/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs b/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs index 803f86e0fb101..ce0bc33905fe5 100644 --- a/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs +++ b/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn reverse(v: &mut [usize]) { v.reverse(); diff --git a/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs index a5fac127356c8..066b33e007b89 100644 --- a/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn bar(v: &mut [usize]) { v.reverse(); diff --git a/src/test/run-pass/compare-generic-enums.rs b/src/test/run-pass/compare-generic-enums.rs index 69945584876d0..228a73326e117 100644 --- a/src/test/run-pass/compare-generic-enums.rs +++ b/src/test/run-pass/compare-generic-enums.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 type an_int = isize; diff --git a/src/test/run-pass/concat.rs b/src/test/run-pass/concat.rs index 7441d1f21b0f9..9a2390a9e68d3 100644 --- a/src/test/run-pass/concat.rs +++ b/src/test/run-pass/concat.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { assert_eq!(format!(concat!("foo", "bar", "{}"), "baz"), "foobarbaz".to_string()); diff --git a/src/test/run-pass/conditional-compile.rs b/src/test/run-pass/conditional-compile.rs index e6660bb9ae880..5891d9f1aa019 100644 --- a/src/test/run-pass/conditional-compile.rs +++ b/src/test/run-pass/conditional-compile.rs @@ -9,7 +9,6 @@ // except according to those terms. // Crate use statements -// pretty-expanded FIXME #23616 #[cfg(bogus)] use flippity; diff --git a/src/test/run-pass/conditional-debug-macro-off.rs b/src/test/run-pass/conditional-debug-macro-off.rs index 192e647f5cb20..c6beb5ba35875 100644 --- a/src/test/run-pass/conditional-debug-macro-off.rs +++ b/src/test/run-pass/conditional-debug-macro-off.rs @@ -11,7 +11,6 @@ // compile-flags: -C debug-assertions=no // exec-env:RUST_LOG=conditional-debug-macro-off=4 -// pretty-expanded FIXME #23616 #![feature(rustc_private)] diff --git a/src/test/run-pass/const-autoderef.rs b/src/test/run-pass/const-autoderef.rs index 1349b7f814bb0..69173e35e2ce3 100644 --- a/src/test/run-pass/const-autoderef.rs +++ b/src/test/run-pass/const-autoderef.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 static A: [u8; 1] = ['h' as u8]; static B: u8 = (&A)[0]; diff --git a/src/test/run-pass/const-big-enum.rs b/src/test/run-pass/const-big-enum.rs index 158c695c548d2..125aefe036dc6 100644 --- a/src/test/run-pass/const-big-enum.rs +++ b/src/test/run-pass/const-big-enum.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum Foo { Bar(u32), diff --git a/src/test/run-pass/const-binops.rs b/src/test/run-pass/const-binops.rs index 1a95220cda59c..4b32ee352311d 100644 --- a/src/test/run-pass/const-binops.rs +++ b/src/test/run-pass/const-binops.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! assert_approx_eq { ($a:expr, $b:expr) => ({ diff --git a/src/test/run-pass/const-block-cross-crate-fn.rs b/src/test/run-pass/const-block-cross-crate-fn.rs index 853e8dc62bb70..6fa6feffbfa00 100644 --- a/src/test/run-pass/const-block-cross-crate-fn.rs +++ b/src/test/run-pass/const-block-cross-crate-fn.rs @@ -10,7 +10,6 @@ // aux-build:cci_const_block.rs -// pretty-expanded FIXME #23616 extern crate cci_const_block; diff --git a/src/test/run-pass/const-block-item-macro-codegen.rs b/src/test/run-pass/const-block-item-macro-codegen.rs index b9e8dbf41d77f..8a4b220a3763c 100644 --- a/src/test/run-pass/const-block-item-macro-codegen.rs +++ b/src/test/run-pass/const-block-item-macro-codegen.rs @@ -11,7 +11,6 @@ // General test that function items in static blocks // can be generated with a macro. -// pretty-expanded FIXME #23616 struct MyType { desc: &'static str, diff --git a/src/test/run-pass/const-block-item.rs b/src/test/run-pass/const-block-item.rs index 897e53822614d..b616b1f610325 100644 --- a/src/test/run-pass/const-block-item.rs +++ b/src/test/run-pass/const-block-item.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod foo { pub trait Value { diff --git a/src/test/run-pass/const-block.rs b/src/test/run-pass/const-block.rs index 1337a91fe05d6..e56d01d7ba8ce 100644 --- a/src/test/run-pass/const-block.rs +++ b/src/test/run-pass/const-block.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(dead_code)] #![allow(unused_unsafe)] diff --git a/src/test/run-pass/const-cast-ptr-int.rs b/src/test/run-pass/const-cast-ptr-int.rs index bbe3020ea1c65..e7674f893d377 100644 --- a/src/test/run-pass/const-cast-ptr-int.rs +++ b/src/test/run-pass/const-cast-ptr-int.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::ptr; diff --git a/src/test/run-pass/const-cast.rs b/src/test/run-pass/const-cast.rs index f660dc5fa450e..411df2b3e0759 100644 --- a/src/test/run-pass/const-cast.rs +++ b/src/test/run-pass/const-cast.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(libc)] diff --git a/src/test/run-pass/const-const.rs b/src/test/run-pass/const-const.rs index d75a5a7eb1c3b..b28017b85ad61 100644 --- a/src/test/run-pass/const-const.rs +++ b/src/test/run-pass/const-const.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const a: isize = 1; const b: isize = a + 2; diff --git a/src/test/run-pass/const-contents.rs b/src/test/run-pass/const-contents.rs index 2dfb88dee0bb8..0d9d0e0e0aa73 100644 --- a/src/test/run-pass/const-contents.rs +++ b/src/test/run-pass/const-contents.rs @@ -10,7 +10,6 @@ // Issue #570 -// pretty-expanded FIXME #23616 static lsl : isize = 1 << 2; static add : isize = 1 + 2; diff --git a/src/test/run-pass/const-cross-crate-const.rs b/src/test/run-pass/const-cross-crate-const.rs index e36a55361ec28..d66c335db2e87 100644 --- a/src/test/run-pass/const-cross-crate-const.rs +++ b/src/test/run-pass/const-cross-crate-const.rs @@ -10,7 +10,6 @@ // aux-build:cci_const.rs -// pretty-expanded FIXME #23616 extern crate cci_const; static foo: &'static str = cci_const::foopy; diff --git a/src/test/run-pass/const-cross-crate-extern.rs b/src/test/run-pass/const-cross-crate-extern.rs index 98f42f91245cd..bbe31ceed33cf 100644 --- a/src/test/run-pass/const-cross-crate-extern.rs +++ b/src/test/run-pass/const-cross-crate-extern.rs @@ -10,7 +10,6 @@ // aux-build:cci_const.rs -// pretty-expanded FIXME #23616 extern crate cci_const; use cci_const::bar; diff --git a/src/test/run-pass/const-deref.rs b/src/test/run-pass/const-deref.rs index 1648332fe2c39..f5407f0c81523 100644 --- a/src/test/run-pass/const-deref.rs +++ b/src/test/run-pass/const-deref.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const C: &'static isize = &1000; static D: isize = *C; diff --git a/src/test/run-pass/const-enum-byref-self.rs b/src/test/run-pass/const-enum-byref-self.rs index e99e1aac8afdb..57470c4a67e26 100644 --- a/src/test/run-pass/const-enum-byref-self.rs +++ b/src/test/run-pass/const-enum-byref-self.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V, VV(isize) } static C: E = E::V; diff --git a/src/test/run-pass/const-enum-byref.rs b/src/test/run-pass/const-enum-byref.rs index 4905eaace6820..e3f1d5d35320c 100644 --- a/src/test/run-pass/const-enum-byref.rs +++ b/src/test/run-pass/const-enum-byref.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V, VV(isize) } static C: E = E::V; diff --git a/src/test/run-pass/const-enum-cast.rs b/src/test/run-pass/const-enum-cast.rs index 3d73933c6f638..38f21f7e95962 100644 --- a/src/test/run-pass/const-enum-cast.rs +++ b/src/test/run-pass/const-enum-cast.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum A { A1, A2 } enum B { B1=0, B2=2 } diff --git a/src/test/run-pass/const-enum-ptr.rs b/src/test/run-pass/const-enum-ptr.rs index d34b5381df9bf..40a1c99e987db 100644 --- a/src/test/run-pass/const-enum-ptr.rs +++ b/src/test/run-pass/const-enum-ptr.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V0, V1(isize) } static C: &'static E = &E::V0; diff --git a/src/test/run-pass/const-enum-struct.rs b/src/test/run-pass/const-enum-struct.rs index 71a9703ec311a..46c4f82eb98e1 100644 --- a/src/test/run-pass/const-enum-struct.rs +++ b/src/test/run-pass/const-enum-struct.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V16(u16), V32(u32) } struct S { a: E, b: u16, c: u16 } diff --git a/src/test/run-pass/const-enum-struct2.rs b/src/test/run-pass/const-enum-struct2.rs index ca56cb5b01a99..e356ecb385b98 100644 --- a/src/test/run-pass/const-enum-struct2.rs +++ b/src/test/run-pass/const-enum-struct2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V0, V16(u16) } struct S { a: E, b: u16, c: u16 } diff --git a/src/test/run-pass/const-enum-structlike.rs b/src/test/run-pass/const-enum-structlike.rs index 113f20e21e1df..6c8786dee6782 100644 --- a/src/test/run-pass/const-enum-structlike.rs +++ b/src/test/run-pass/const-enum-structlike.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { S0 { s: String }, diff --git a/src/test/run-pass/const-enum-tuple.rs b/src/test/run-pass/const-enum-tuple.rs index 2ab28f5fb2377..476defaa524a0 100644 --- a/src/test/run-pass/const-enum-tuple.rs +++ b/src/test/run-pass/const-enum-tuple.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V16(u16), V32(u32) } static C: (E, u16, u16) = (E::V16(0xDEAD), 0x600D, 0xBAD); diff --git a/src/test/run-pass/const-enum-tuple2.rs b/src/test/run-pass/const-enum-tuple2.rs index fe1b2e051c479..61043ef75a4c5 100644 --- a/src/test/run-pass/const-enum-tuple2.rs +++ b/src/test/run-pass/const-enum-tuple2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V0, V16(u16) } static C: (E, u16, u16) = (E::V0, 0x600D, 0xBAD); diff --git a/src/test/run-pass/const-enum-tuplestruct.rs b/src/test/run-pass/const-enum-tuplestruct.rs index 7f9de49404d3a..f574508522b26 100644 --- a/src/test/run-pass/const-enum-tuplestruct.rs +++ b/src/test/run-pass/const-enum-tuplestruct.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V16(u16), V32(u32) } struct S(E, u16, u16); diff --git a/src/test/run-pass/const-enum-tuplestruct2.rs b/src/test/run-pass/const-enum-tuplestruct2.rs index 3d7b6c9f49f78..88cfc0dec7028 100644 --- a/src/test/run-pass/const-enum-tuplestruct2.rs +++ b/src/test/run-pass/const-enum-tuplestruct2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V0, V16(u16) } struct S(E, u16, u16); diff --git a/src/test/run-pass/const-enum-vec-index.rs b/src/test/run-pass/const-enum-vec-index.rs index fcaf8b8844b07..2f1cd8dbf9b12 100644 --- a/src/test/run-pass/const-enum-vec-index.rs +++ b/src/test/run-pass/const-enum-vec-index.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V1(isize), V0 } const C: &'static [E] = &[E::V0, E::V1(0xDEADBEE)]; diff --git a/src/test/run-pass/const-enum-vec-ptr.rs b/src/test/run-pass/const-enum-vec-ptr.rs index 936d72ac65e2f..de94527a60486 100644 --- a/src/test/run-pass/const-enum-vec-ptr.rs +++ b/src/test/run-pass/const-enum-vec-ptr.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V1(isize), V0 } static C: &'static [E] = &[E::V0, E::V1(0xDEADBEE), E::V0]; diff --git a/src/test/run-pass/const-enum-vector.rs b/src/test/run-pass/const-enum-vector.rs index 6fdf0c3948fa0..8d43a76bc28c3 100644 --- a/src/test/run-pass/const-enum-vector.rs +++ b/src/test/run-pass/const-enum-vector.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V1(isize), V0 } static C: [E; 3] = [E::V0, E::V1(0xDEADBEE), E::V0]; diff --git a/src/test/run-pass/const-extern-function.rs b/src/test/run-pass/const-extern-function.rs index ff829711a4c6c..214b0400e8631 100644 --- a/src/test/run-pass/const-extern-function.rs +++ b/src/test/run-pass/const-extern-function.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 extern fn foopy() {} diff --git a/src/test/run-pass/const-fn-val.rs b/src/test/run-pass/const-fn-val.rs index 3e1058dc27d99..85c92dda434a6 100644 --- a/src/test/run-pass/const-fn-val.rs +++ b/src/test/run-pass/const-fn-val.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn foo() -> isize { return 0xca7f000d; diff --git a/src/test/run-pass/const-negative.rs b/src/test/run-pass/const-negative.rs index 59b2c3e36aaf9..7f26a9773396d 100644 --- a/src/test/run-pass/const-negative.rs +++ b/src/test/run-pass/const-negative.rs @@ -10,7 +10,6 @@ // Issue #358 -// pretty-expanded FIXME #23616 static toplevel_mod: isize = -1; diff --git a/src/test/run-pass/const-nullary-enum.rs b/src/test/run-pass/const-nullary-enum.rs index fcad89470d7c5..b3f6549ef0167 100644 --- a/src/test/run-pass/const-nullary-enum.rs +++ b/src/test/run-pass/const-nullary-enum.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum Foo { Bar, diff --git a/src/test/run-pass/const-nullary-univariant-enum.rs b/src/test/run-pass/const-nullary-univariant-enum.rs index 51926ececc2b1..b1b7f782cd04a 100644 --- a/src/test/run-pass/const-nullary-univariant-enum.rs +++ b/src/test/run-pass/const-nullary-univariant-enum.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] enum Foo { diff --git a/src/test/run-pass/const-region-ptrs-noncopy.rs b/src/test/run-pass/const-region-ptrs-noncopy.rs index 8932853fbf485..9a1f747ce59fb 100644 --- a/src/test/run-pass/const-region-ptrs-noncopy.rs +++ b/src/test/run-pass/const-region-ptrs-noncopy.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 type Big = [u64; 8]; struct Pair<'a> { a: isize, b: &'a Big } diff --git a/src/test/run-pass/const-str-ptr.rs b/src/test/run-pass/const-str-ptr.rs index c5ff134ff0e9b..1cdb98a8bc05b 100644 --- a/src/test/run-pass/const-str-ptr.rs +++ b/src/test/run-pass/const-str-ptr.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::{str, string}; diff --git a/src/test/run-pass/const-tuple-struct.rs b/src/test/run-pass/const-tuple-struct.rs index ccf1b06bacb5f..ddc50fc6646f2 100644 --- a/src/test/run-pass/const-tuple-struct.rs +++ b/src/test/run-pass/const-tuple-struct.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Bar(isize, isize); diff --git a/src/test/run-pass/consts-in-patterns.rs b/src/test/run-pass/consts-in-patterns.rs index c2f7cf4d62568..36e6e160a3bd2 100644 --- a/src/test/run-pass/consts-in-patterns.rs +++ b/src/test/run-pass/consts-in-patterns.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const FOO: isize = 10; const BAR: isize = 3; diff --git a/src/test/run-pass/cross-crate-newtype-struct-pat.rs b/src/test/run-pass/cross-crate-newtype-struct-pat.rs index 986108c5d8fa6..7eae9017420d7 100644 --- a/src/test/run-pass/cross-crate-newtype-struct-pat.rs +++ b/src/test/run-pass/cross-crate-newtype-struct-pat.rs @@ -10,7 +10,6 @@ // aux-build:newtype_struct_xc.rs -// pretty-expanded FIXME #23616 extern crate newtype_struct_xc; diff --git a/src/test/run-pass/deep.rs b/src/test/run-pass/deep.rs index 16636fadbf8dc..f8e690cf29e07 100644 --- a/src/test/run-pass/deep.rs +++ b/src/test/run-pass/deep.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 fn f(x: isize) -> isize { if x == 1 { return 1; } else { let y: isize = 1 + f(x - 1); return y; } diff --git a/src/test/run-pass/deref-mut-on-ref.rs b/src/test/run-pass/deref-mut-on-ref.rs index 8820003d3b24d..98441d7daaad7 100644 --- a/src/test/run-pass/deref-mut-on-ref.rs +++ b/src/test/run-pass/deref-mut-on-ref.rs @@ -10,7 +10,6 @@ // Test that `&mut T` implements `DerefMut` -// pretty-expanded FIXME #23616 use std::ops::{Deref, DerefMut}; diff --git a/src/test/run-pass/deref-on-ref.rs b/src/test/run-pass/deref-on-ref.rs index 84bfbd82297a7..383c8197f9473 100644 --- a/src/test/run-pass/deref-on-ref.rs +++ b/src/test/run-pass/deref-on-ref.rs @@ -10,7 +10,6 @@ // Test that `&T` and `&mut T` implement `Deref` -// pretty-expanded FIXME #23616 use std::ops::Deref; diff --git a/src/test/run-pass/deref-rc.rs b/src/test/run-pass/deref-rc.rs index 761b29258f2af..b84d78b4f4fbd 100644 --- a/src/test/run-pass/deref-rc.rs +++ b/src/test/run-pass/deref-rc.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::rc::Rc; diff --git a/src/test/run-pass/deriving-cmp-generic-enum.rs b/src/test/run-pass/deriving-cmp-generic-enum.rs index 07ad8f706eb5c..b1cd1877a7667 100644 --- a/src/test/run-pass/deriving-cmp-generic-enum.rs +++ b/src/test/run-pass/deriving-cmp-generic-enum.rs @@ -10,7 +10,6 @@ // no-pretty-expanded FIXME #15189 -// pretty-expanded FIXME #23616 #[derive(PartialEq, Eq, PartialOrd, Ord)] enum E { diff --git a/src/test/run-pass/deriving-cmp-generic-struct-enum.rs b/src/test/run-pass/deriving-cmp-generic-struct-enum.rs index 5f7d184f1949d..14f7862ef21fc 100644 --- a/src/test/run-pass/deriving-cmp-generic-struct-enum.rs +++ b/src/test/run-pass/deriving-cmp-generic-struct-enum.rs @@ -10,7 +10,6 @@ // no-pretty-expanded FIXME #15189 -// pretty-expanded FIXME #23616 #[derive(PartialEq, Eq, PartialOrd, Ord)] enum ES { diff --git a/src/test/run-pass/deriving-cmp-generic-struct.rs b/src/test/run-pass/deriving-cmp-generic-struct.rs index ea0017380b275..5c7d806f519d1 100644 --- a/src/test/run-pass/deriving-cmp-generic-struct.rs +++ b/src/test/run-pass/deriving-cmp-generic-struct.rs @@ -10,7 +10,6 @@ // no-pretty-expanded FIXME #15189 -// pretty-expanded FIXME #23616 #[derive(PartialEq, Eq, PartialOrd, Ord)] struct S { diff --git a/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs b/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs index 702071676b90e..b7bfb91b278a0 100644 --- a/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs +++ b/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs @@ -10,7 +10,6 @@ // no-pretty-expanded FIXME #15189 -// pretty-expanded FIXME #23616 #[derive(PartialEq, Eq, PartialOrd, Ord)] struct TS(T,T); diff --git a/src/test/run-pass/deriving-cmp-shortcircuit.rs b/src/test/run-pass/deriving-cmp-shortcircuit.rs index 1669f3fdd3d9a..e22e4767d521f 100644 --- a/src/test/run-pass/deriving-cmp-shortcircuit.rs +++ b/src/test/run-pass/deriving-cmp-shortcircuit.rs @@ -12,7 +12,6 @@ // where possible, by having a type that panics when compared as the // second element, so this passes iff the instances shortcircuit. -// pretty-expanded FIXME #23616 use std::cmp::Ordering; diff --git a/src/test/run-pass/deriving-default-box.rs b/src/test/run-pass/deriving-default-box.rs index 574a620ef0290..dc31e71aad873 100644 --- a/src/test/run-pass/deriving-default-box.rs +++ b/src/test/run-pass/deriving-default-box.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/deriving-encodable-decodable-box.rs b/src/test/run-pass/deriving-encodable-decodable-box.rs index 6ccedb0ad982f..db5a1f3f000a8 100644 --- a/src/test/run-pass/deriving-encodable-decodable-box.rs +++ b/src/test/run-pass/deriving-encodable-decodable-box.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs b/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs index d216062bb2da3..7cc59edfcab0e 100644 --- a/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs +++ b/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs @@ -11,7 +11,6 @@ // This briefly tests the capability of `Cell` and `RefCell` to implement the // `Encodable` and `Decodable` traits via `#[derive(Encodable, Decodable)]` -// pretty-expanded FIXME #23616 #![feature(rustc_private)] diff --git a/src/test/run-pass/deriving-hash.rs b/src/test/run-pass/deriving-hash.rs index ce7ba9f25eb07..287750e5051c7 100644 --- a/src/test/run-pass/deriving-hash.rs +++ b/src/test/run-pass/deriving-hash.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(hash)] diff --git a/src/test/run-pass/deriving-rand.rs b/src/test/run-pass/deriving-rand.rs index b960c2ddd4a43..bc11b55d3105f 100644 --- a/src/test/run-pass/deriving-rand.rs +++ b/src/test/run-pass/deriving-rand.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(rand)] diff --git a/src/test/run-pass/destructure-array-1.rs b/src/test/run-pass/destructure-array-1.rs index e2c96085714ba..0d24f0bd0d7b3 100644 --- a/src/test/run-pass/destructure-array-1.rs +++ b/src/test/run-pass/destructure-array-1.rs @@ -11,7 +11,6 @@ // Ensure that we can do a destructuring bind of a fixed-size array, // even when the element type has a destructor. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-pass/die-macro.rs b/src/test/run-pass/die-macro.rs index 6a81ebe67ba80..0816e258e84a0 100644 --- a/src/test/run-pass/die-macro.rs +++ b/src/test/run-pass/die-macro.rs @@ -10,7 +10,6 @@ // Just testing that panic!() type checks in statement or expr -// pretty-expanded FIXME #23616 #![allow(unreachable_code)] diff --git a/src/test/run-pass/div-mod.rs b/src/test/run-pass/div-mod.rs index 237cfe19dc49b..b6cae71df865d 100644 --- a/src/test/run-pass/div-mod.rs +++ b/src/test/run-pass/div-mod.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let x: isize = 15; diff --git a/src/test/run-pass/drop-struct-as-object.rs b/src/test/run-pass/drop-struct-as-object.rs index efb98160a3e61..33d5c72772c57 100644 --- a/src/test/run-pass/drop-struct-as-object.rs +++ b/src/test/run-pass/drop-struct-as-object.rs @@ -11,7 +11,6 @@ // Test that destructor on a struct runs successfully after the struct // is boxed and converted to an object. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/drop-with-type-ascription-1.rs b/src/test/run-pass/drop-with-type-ascription-1.rs index ea9edff4945fe..9dd458344cb5a 100644 --- a/src/test/run-pass/drop-with-type-ascription-1.rs +++ b/src/test/run-pass/drop-with-type-ascription-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(str_words)] diff --git a/src/test/run-pass/drop-with-type-ascription-2.rs b/src/test/run-pass/drop-with-type-ascription-2.rs index 3d4af80e30bb5..cb3712dea3224 100644 --- a/src/test/run-pass/drop-with-type-ascription-2.rs +++ b/src/test/run-pass/drop-with-type-ascription-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections)] diff --git a/src/test/run-pass/dropck_tarena_sound_drop.rs b/src/test/run-pass/dropck_tarena_sound_drop.rs index df29b8e10c7aa..6ccf6c2fd644d 100644 --- a/src/test/run-pass/dropck_tarena_sound_drop.rs +++ b/src/test/run-pass/dropck_tarena_sound_drop.rs @@ -16,7 +16,6 @@ // shows a similar setup, but restricts `f` so that the struct `C<'a>` // is force-fed a lifetime equal to that of the borrowed arena. -// pretty-expanded FIXME #23616 #![allow(unstable)] #![feature(unsafe_destructor, rustc_private)] diff --git a/src/test/run-pass/dst-deref-mut.rs b/src/test/run-pass/dst-deref-mut.rs index 3b2b7493fd0fa..b031c82a07f3d 100644 --- a/src/test/run-pass/dst-deref-mut.rs +++ b/src/test/run-pass/dst-deref-mut.rs @@ -10,7 +10,6 @@ // Test that a custom deref with a fat pointer return type does not ICE -// pretty-expanded FIXME #23616 use std::ops::{Deref, DerefMut}; diff --git a/src/test/run-pass/dst-deref.rs b/src/test/run-pass/dst-deref.rs index c8e658beef81b..c4666d05fbfe3 100644 --- a/src/test/run-pass/dst-deref.rs +++ b/src/test/run-pass/dst-deref.rs @@ -10,7 +10,6 @@ // Test that a custom deref with a fat pointer return type does not ICE -// pretty-expanded FIXME #23616 use std::ops::Deref; diff --git a/src/test/run-pass/dst-index.rs b/src/test/run-pass/dst-index.rs index df4cd74740cdd..34a187fa6f2d2 100644 --- a/src/test/run-pass/dst-index.rs +++ b/src/test/run-pass/dst-index.rs @@ -11,7 +11,6 @@ // Test that overloaded index expressions with DST result types // work and don't ICE. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/dst-raw.rs b/src/test/run-pass/dst-raw.rs index 5e0e5bd03fe6f..d899de9164071 100644 --- a/src/test/run-pass/dst-raw.rs +++ b/src/test/run-pass/dst-raw.rs @@ -10,7 +10,6 @@ // Test DST raw pointers -// pretty-expanded FIXME #23616 trait Trait { fn foo(&self) -> isize; diff --git a/src/test/run-pass/dst-struct-sole.rs b/src/test/run-pass/dst-struct-sole.rs index 9bf286c434219..d440fb2a216ec 100644 --- a/src/test/run-pass/dst-struct-sole.rs +++ b/src/test/run-pass/dst-struct-sole.rs @@ -10,7 +10,6 @@ // As dst-struct.rs, but the unsized field is the only field in the struct. -// pretty-expanded FIXME #23616 struct Fat { ptr: T diff --git a/src/test/run-pass/dst-struct.rs b/src/test/run-pass/dst-struct.rs index 5198dd43d6db8..8b6db23026b8a 100644 --- a/src/test/run-pass/dst-struct.rs +++ b/src/test/run-pass/dst-struct.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/dst-trait.rs b/src/test/run-pass/dst-trait.rs index 370bc2882271f..4d2b50c08e2f5 100644 --- a/src/test/run-pass/dst-trait.rs +++ b/src/test/run-pass/dst-trait.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/else-if.rs b/src/test/run-pass/else-if.rs index 79c2f45067884..afc1d200b274b 100644 --- a/src/test/run-pass/else-if.rs +++ b/src/test/run-pass/else-if.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { if 1 == 2 { diff --git a/src/test/run-pass/empty-allocation-non-null.rs b/src/test/run-pass/empty-allocation-non-null.rs index cec528fa0401c..af6e321e40aa6 100644 --- a/src/test/run-pass/empty-allocation-non-null.rs +++ b/src/test/run-pass/empty-allocation-non-null.rs @@ -10,7 +10,6 @@ // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. -// pretty-expanded FIXME #23616 pub fn main() { assert!(Some(Box::new(())).is_some()); diff --git a/src/test/run-pass/enum-alignment.rs b/src/test/run-pass/enum-alignment.rs index df779d0d713fd..827894f8f32c9 100644 --- a/src/test/run-pass/enum-alignment.rs +++ b/src/test/run-pass/enum-alignment.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/enum-clike-ffi-as-int.rs b/src/test/run-pass/enum-clike-ffi-as-int.rs index f129a51534143..8be3634c88add 100644 --- a/src/test/run-pass/enum-clike-ffi-as-int.rs +++ b/src/test/run-pass/enum-clike-ffi-as-int.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 /*! * C-like enums have to be represented as LLVM ints, not wrapped in a diff --git a/src/test/run-pass/enum-discr.rs b/src/test/run-pass/enum-discr.rs index 5c01d544cf533..1ff6370136076 100644 --- a/src/test/run-pass/enum-discr.rs +++ b/src/test/run-pass/enum-discr.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum Animal { Cat = 0, diff --git a/src/test/run-pass/enum-discrim-autosizing.rs b/src/test/run-pass/enum-discrim-autosizing.rs index 239f9821b925b..99e44735d0f03 100644 --- a/src/test/run-pass/enum-discrim-autosizing.rs +++ b/src/test/run-pass/enum-discrim-autosizing.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::size_of; diff --git a/src/test/run-pass/enum-discrim-manual-sizing.rs b/src/test/run-pass/enum-discrim-manual-sizing.rs index b23cfa9f32b8e..edad5cc1652da 100644 --- a/src/test/run-pass/enum-discrim-manual-sizing.rs +++ b/src/test/run-pass/enum-discrim-manual-sizing.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::size_of; diff --git a/src/test/run-pass/enum-disr-val-pretty.rs b/src/test/run-pass/enum-disr-val-pretty.rs index 9a2f45d00790e..cf66725178011 100644 --- a/src/test/run-pass/enum-disr-val-pretty.rs +++ b/src/test/run-pass/enum-disr-val-pretty.rs @@ -10,7 +10,6 @@ // pp-exact -// pretty-expanded FIXME #23616 enum color { red = 1, green, blue, imaginary = -1, } diff --git a/src/test/run-pass/enum-null-pointer-opt.rs b/src/test/run-pass/enum-null-pointer-opt.rs index 9fc799a97f6b9..499d131947a38 100644 --- a/src/test/run-pass/enum-null-pointer-opt.rs +++ b/src/test/run-pass/enum-null-pointer-opt.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/enum-nullable-const-null-with-fields.rs b/src/test/run-pass/enum-nullable-const-null-with-fields.rs index 3a7c7ea9a714b..1342c4e104de5 100644 --- a/src/test/run-pass/enum-nullable-const-null-with-fields.rs +++ b/src/test/run-pass/enum-nullable-const-null-with-fields.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::result::Result; use std::result::Result::Ok; diff --git a/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs b/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs index 99554aafb0427..c8a1047cfa818 100644 --- a/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs +++ b/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/env-home-dir.rs b/src/test/run-pass/env-home-dir.rs index 7fb96112125af..efe72729817e8 100644 --- a/src/test/run-pass/env-home-dir.rs +++ b/src/test/run-pass/env-home-dir.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(path)] diff --git a/src/test/run-pass/env-vars.rs b/src/test/run-pass/env-vars.rs index 33bc6c596dbd0..d86f63c9cb91d 100644 --- a/src/test/run-pass/env-vars.rs +++ b/src/test/run-pass/env-vars.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::env::*; diff --git a/src/test/run-pass/eq-multidispatch.rs b/src/test/run-pass/eq-multidispatch.rs index 3ca254021e5b9..bf8b089a830c2 100644 --- a/src/test/run-pass/eq-multidispatch.rs +++ b/src/test/run-pass/eq-multidispatch.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(PartialEq)] struct Bar; diff --git a/src/test/run-pass/estr-uniq.rs b/src/test/run-pass/estr-uniq.rs index 0b24658a8f331..4dfb15418405d 100644 --- a/src/test/run-pass/estr-uniq.rs +++ b/src/test/run-pass/estr-uniq.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(dead_assignment)] diff --git a/src/test/run-pass/exec-env.rs b/src/test/run-pass/exec-env.rs index a24930732474f..d17056e6d799d 100644 --- a/src/test/run-pass/exec-env.rs +++ b/src/test/run-pass/exec-env.rs @@ -10,7 +10,6 @@ // exec-env:TEST_EXEC_ENV=22 -// pretty-expanded FIXME #23616 use std::env; diff --git a/src/test/run-pass/explicit-self-generic.rs b/src/test/run-pass/explicit-self-generic.rs index ee50d3bdf0ee8..1b50d3028b1e2 100644 --- a/src/test/run-pass/explicit-self-generic.rs +++ b/src/test/run-pass/explicit-self-generic.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/explicit-self-objects-uniq.rs b/src/test/run-pass/explicit-self-objects-uniq.rs index 08ea638f93a56..4021ae89e3629 100644 --- a/src/test/run-pass/explicit-self-objects-uniq.rs +++ b/src/test/run-pass/explicit-self-objects-uniq.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/explicit-self.rs b/src/test/run-pass/explicit-self.rs index b81090555ea64..d2a0d60eb6614 100644 --- a/src/test/run-pass/explicit-self.rs +++ b/src/test/run-pass/explicit-self.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/expr-block-fn.rs b/src/test/run-pass/expr-block-fn.rs index c88721471b64c..67e41aad6971b 100644 --- a/src/test/run-pass/expr-block-fn.rs +++ b/src/test/run-pass/expr-block-fn.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 fn test_fn() { fn ten() -> isize { return 10; } diff --git a/src/test/run-pass/expr-block-generic-unique2.rs b/src/test/run-pass/expr-block-generic-unique2.rs index bd2936773953b..5477a9227aa1d 100644 --- a/src/test/run-pass/expr-block-generic-unique2.rs +++ b/src/test/run-pass/expr-block-generic-unique2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/expr-block-generic.rs b/src/test/run-pass/expr-block-generic.rs index d26c6e62f536e..8795962bebdd8 100644 --- a/src/test/run-pass/expr-block-generic.rs +++ b/src/test/run-pass/expr-block-generic.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn test_generic(expected: T, eq: F) where F: FnOnce(T, T) -> bool { let actual: T = { expected.clone() }; diff --git a/src/test/run-pass/expr-block-slot.rs b/src/test/run-pass/expr-block-slot.rs index 57b5a426f5c5c..d9b4c95bc24d1 100644 --- a/src/test/run-pass/expr-block-slot.rs +++ b/src/test/run-pass/expr-block-slot.rs @@ -10,7 +10,6 @@ // Regression test for issue #377 -// pretty-expanded FIXME #23616 struct A { a: isize } struct V { v: isize } diff --git a/src/test/run-pass/expr-block-unique.rs b/src/test/run-pass/expr-block-unique.rs index 496a575c6c8b5..7ad024186015b 100644 --- a/src/test/run-pass/expr-block-unique.rs +++ b/src/test/run-pass/expr-block-unique.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/expr-block.rs b/src/test/run-pass/expr-block.rs index 64f86237ab3bb..38be041938b3c 100644 --- a/src/test/run-pass/expr-block.rs +++ b/src/test/run-pass/expr-block.rs @@ -13,7 +13,6 @@ // Tests for standalone blocks as expressions -// pretty-expanded FIXME #23616 fn test_basic() { let rs: bool = { true }; assert!((rs)); } diff --git a/src/test/run-pass/expr-copy.rs b/src/test/run-pass/expr-copy.rs index ca394f991f29b..99e74a6b8564d 100644 --- a/src/test/run-pass/expr-copy.rs +++ b/src/test/run-pass/expr-copy.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn f(arg: &mut A) { arg.a = 100; diff --git a/src/test/run-pass/expr-fn.rs b/src/test/run-pass/expr-fn.rs index 0c9151cec7df4..aeca388d317b6 100644 --- a/src/test/run-pass/expr-fn.rs +++ b/src/test/run-pass/expr-fn.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn test_int() { fn f() -> isize { 10 } diff --git a/src/test/run-pass/expr-if-generic.rs b/src/test/run-pass/expr-if-generic.rs index 47e79de6b1124..94c6b70bb62f3 100644 --- a/src/test/run-pass/expr-if-generic.rs +++ b/src/test/run-pass/expr-if-generic.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn test_generic(expected: T, not_expected: T, eq: F) where T: Clone, diff --git a/src/test/run-pass/expr-if-panic-all.rs b/src/test/run-pass/expr-if-panic-all.rs index 1e631c204798a..43110533b6dc6 100644 --- a/src/test/run-pass/expr-if-panic-all.rs +++ b/src/test/run-pass/expr-if-panic-all.rs @@ -10,7 +10,6 @@ // When all branches of an if expression result in panic, the entire if // expression results in panic. -// pretty-expanded FIXME #23616 pub fn main() { let _x = if true { diff --git a/src/test/run-pass/expr-if-panic.rs b/src/test/run-pass/expr-if-panic.rs index e8594db80393b..c7f10b66ca3c7 100644 --- a/src/test/run-pass/expr-if-panic.rs +++ b/src/test/run-pass/expr-if-panic.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn test_if_panic() { let x = if false { panic!() } else { 10 }; diff --git a/src/test/run-pass/expr-if-unique.rs b/src/test/run-pass/expr-if-unique.rs index 99c5053588b1c..12000fd54e7e7 100644 --- a/src/test/run-pass/expr-if-unique.rs +++ b/src/test/run-pass/expr-if-unique.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/expr-if.rs b/src/test/run-pass/expr-if.rs index 345f17707c408..e8458e320113b 100644 --- a/src/test/run-pass/expr-if.rs +++ b/src/test/run-pass/expr-if.rs @@ -13,7 +13,6 @@ // Tests for if as expressions -// pretty-expanded FIXME #23616 fn test_if() { let rs: bool = if true { true } else { false }; assert!((rs)); } diff --git a/src/test/run-pass/expr-match-generic-unique1.rs b/src/test/run-pass/expr-match-generic-unique1.rs index 7cd0f6a758999..738fcecb2e0db 100644 --- a/src/test/run-pass/expr-match-generic-unique1.rs +++ b/src/test/run-pass/expr-match-generic-unique1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/expr-match-generic-unique2.rs b/src/test/run-pass/expr-match-generic-unique2.rs index 95f47d005d3d6..88ea241524109 100644 --- a/src/test/run-pass/expr-match-generic-unique2.rs +++ b/src/test/run-pass/expr-match-generic-unique2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/expr-match-generic.rs b/src/test/run-pass/expr-match-generic.rs index f8e82de9a0a36..509106289d079 100644 --- a/src/test/run-pass/expr-match-generic.rs +++ b/src/test/run-pass/expr-match-generic.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 type compare = extern "Rust" fn(T, T) -> bool; diff --git a/src/test/run-pass/expr-match-panic-all.rs b/src/test/run-pass/expr-match-panic-all.rs index 664ead10aae09..e712d552a8107 100644 --- a/src/test/run-pass/expr-match-panic-all.rs +++ b/src/test/run-pass/expr-match-panic-all.rs @@ -13,7 +13,6 @@ // When all branches of a match expression result in panic, the entire // match expression results in panic. -// pretty-expanded FIXME #23616 pub fn main() { let _x = diff --git a/src/test/run-pass/expr-match-panic.rs b/src/test/run-pass/expr-match-panic.rs index 40e7a6175cf86..89dc7b09c7b15 100644 --- a/src/test/run-pass/expr-match-panic.rs +++ b/src/test/run-pass/expr-match-panic.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn test_simple() { let r = match true { true => { true } false => { panic!() } }; diff --git a/src/test/run-pass/expr-match-unique.rs b/src/test/run-pass/expr-match-unique.rs index 51eda4c7663a8..e752c20a51242 100644 --- a/src/test/run-pass/expr-match-unique.rs +++ b/src/test/run-pass/expr-match-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/expr-match.rs b/src/test/run-pass/expr-match.rs index 2282391ef6fb4..580ee52ed3645 100644 --- a/src/test/run-pass/expr-match.rs +++ b/src/test/run-pass/expr-match.rs @@ -13,7 +13,6 @@ // Tests for using match as an expression -// pretty-expanded FIXME #23616 fn test_basic() { let mut rs: bool = match true { true => { true } false => { false } }; diff --git a/src/test/run-pass/ext-expand-inner-exprs.rs b/src/test/run-pass/ext-expand-inner-exprs.rs index 46cd73e11527c..90ca31e80be3a 100644 --- a/src/test/run-pass/ext-expand-inner-exprs.rs +++ b/src/test/run-pass/ext-expand-inner-exprs.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 static FOO : &'static str = concat!(concat!("hel", "lo"), "world"); diff --git a/src/test/run-pass/exterior.rs b/src/test/run-pass/exterior.rs index 9a039e8bc3539..3474e2eefb7c7 100644 --- a/src/test/run-pass/exterior.rs +++ b/src/test/run-pass/exterior.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 use std::cell::Cell; diff --git a/src/test/run-pass/extern-call-direct.rs b/src/test/run-pass/extern-call-direct.rs index 38cd4a8d79d0d..ec6b6c8d39fad 100644 --- a/src/test/run-pass/extern-call-direct.rs +++ b/src/test/run-pass/extern-call-direct.rs @@ -10,7 +10,6 @@ // Test direct calls to extern fns. -// pretty-expanded FIXME #23616 extern fn f(x: usize) -> usize { x * 2 } diff --git a/src/test/run-pass/extern-compare-with-return-type.rs b/src/test/run-pass/extern-compare-with-return-type.rs index 09411c9c6eb29..6535ae2fca946 100644 --- a/src/test/run-pass/extern-compare-with-return-type.rs +++ b/src/test/run-pass/extern-compare-with-return-type.rs @@ -10,7 +10,6 @@ // Tests that we can compare various kinds of extern fn signatures. -// pretty-expanded FIXME #23616 extern fn voidret1() {} extern fn voidret2() {} diff --git a/src/test/run-pass/extern-methods.rs b/src/test/run-pass/extern-methods.rs index 246f65931b70e..28a076113d1f0 100644 --- a/src/test/run-pass/extern-methods.rs +++ b/src/test/run-pass/extern-methods.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/extern-pass-char.rs b/src/test/run-pass/extern-pass-char.rs index bbdf5cf64a127..e75aa2d72c925 100644 --- a/src/test/run-pass/extern-pass-char.rs +++ b/src/test/run-pass/extern-pass-char.rs @@ -10,7 +10,6 @@ // Test a function that takes/returns a u8. -// pretty-expanded FIXME #23616 #[link(name = "rust_test_helpers")] extern { diff --git a/src/test/run-pass/extern-pass-double.rs b/src/test/run-pass/extern-pass-double.rs index 24c461f43adf8..e92f9b6a1a172 100644 --- a/src/test/run-pass/extern-pass-double.rs +++ b/src/test/run-pass/extern-pass-double.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[link(name = "rust_test_helpers")] extern { diff --git a/src/test/run-pass/extern-pass-u32.rs b/src/test/run-pass/extern-pass-u32.rs index f93d7a3ff9614..0753ea1bcfead 100644 --- a/src/test/run-pass/extern-pass-u32.rs +++ b/src/test/run-pass/extern-pass-u32.rs @@ -10,7 +10,6 @@ // Test a function that takes/returns a u32. -// pretty-expanded FIXME #23616 #[link(name = "rust_test_helpers")] extern { diff --git a/src/test/run-pass/extern-pass-u64.rs b/src/test/run-pass/extern-pass-u64.rs index 961a3dce16813..89faa3bb47141 100644 --- a/src/test/run-pass/extern-pass-u64.rs +++ b/src/test/run-pass/extern-pass-u64.rs @@ -10,7 +10,6 @@ // Test a call to a function that takes/returns a u64. -// pretty-expanded FIXME #23616 #[link(name = "rust_test_helpers")] extern { diff --git a/src/test/run-pass/extern-return-TwoU16s.rs b/src/test/run-pass/extern-return-TwoU16s.rs index f149a1346229a..3c58646e0c302 100644 --- a/src/test/run-pass/extern-return-TwoU16s.rs +++ b/src/test/run-pass/extern-return-TwoU16s.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub struct TwoU16s { one: u16, two: u16 diff --git a/src/test/run-pass/extern-return-TwoU32s.rs b/src/test/run-pass/extern-return-TwoU32s.rs index 4e9c44ef75eec..0eb6be2d687a4 100644 --- a/src/test/run-pass/extern-return-TwoU32s.rs +++ b/src/test/run-pass/extern-return-TwoU32s.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub struct TwoU32s { one: u32, two: u32 diff --git a/src/test/run-pass/extern-return-TwoU64s.rs b/src/test/run-pass/extern-return-TwoU64s.rs index fffd77fa89735..d5eab86351e10 100644 --- a/src/test/run-pass/extern-return-TwoU64s.rs +++ b/src/test/run-pass/extern-return-TwoU64s.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub struct TwoU64s { one: u64, two: u64 diff --git a/src/test/run-pass/extern-return-TwoU8s.rs b/src/test/run-pass/extern-return-TwoU8s.rs index fdf43d4332a9d..d8f476bcd0cbb 100644 --- a/src/test/run-pass/extern-return-TwoU8s.rs +++ b/src/test/run-pass/extern-return-TwoU8s.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub struct TwoU8s { one: u8, two: u8 diff --git a/src/test/run-pass/extern-take-value.rs b/src/test/run-pass/extern-take-value.rs index c016e4e62f56f..7ef87b9409d51 100644 --- a/src/test/run-pass/extern-take-value.rs +++ b/src/test/run-pass/extern-take-value.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 extern fn f() { } diff --git a/src/test/run-pass/extoption_env-not-defined.rs b/src/test/run-pass/extoption_env-not-defined.rs index aaa8f6cf26f1d..352f68da9854f 100644 --- a/src/test/run-pass/extoption_env-not-defined.rs +++ b/src/test/run-pass/extoption_env-not-defined.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { assert!(option_env!("__HOPEFULLY_DOESNT_EXIST__").is_none()); diff --git a/src/test/run-pass/field-destruction-order.rs b/src/test/run-pass/field-destruction-order.rs index aab32a7e7bd37..624167db36da3 100644 --- a/src/test/run-pass/field-destruction-order.rs +++ b/src/test/run-pass/field-destruction-order.rs @@ -21,7 +21,6 @@ // declarations, but we currently run them top-to-bottom. I don't think the // order really matters that much as long as we define what it is. -// pretty-expanded FIXME #23616 struct A; struct B; diff --git a/src/test/run-pass/fixed_length_copy.rs b/src/test/run-pass/fixed_length_copy.rs index 019537a2ab8b0..eefd94475358c 100644 --- a/src/test/run-pass/fixed_length_copy.rs +++ b/src/test/run-pass/fixed_length_copy.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let arr = [1,2,3]; diff --git a/src/test/run-pass/float2.rs b/src/test/run-pass/float2.rs index f84cbe5235467..e9f6e0f51b4ec 100644 --- a/src/test/run-pass/float2.rs +++ b/src/test/run-pass/float2.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let a = 1.5e6f64; diff --git a/src/test/run-pass/floatlits.rs b/src/test/run-pass/floatlits.rs index d45c689bfdaa7..d133f3463a3f2 100644 --- a/src/test/run-pass/floatlits.rs +++ b/src/test/run-pass/floatlits.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let f = 4.999999999999f64; diff --git a/src/test/run-pass/fn-bare-assign.rs b/src/test/run-pass/fn-bare-assign.rs index d83dc7858056f..2d3d4cbffd00d 100644 --- a/src/test/run-pass/fn-bare-assign.rs +++ b/src/test/run-pass/fn-bare-assign.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn f(i: isize, called: &mut bool) { assert_eq!(i, 10); diff --git a/src/test/run-pass/fn-bare-size.rs b/src/test/run-pass/fn-bare-size.rs index 117cf13584f18..3ed4f103af081 100644 --- a/src/test/run-pass/fn-bare-size.rs +++ b/src/test/run-pass/fn-bare-size.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/fn-bare-spawn.rs b/src/test/run-pass/fn-bare-spawn.rs index 0a3c891627068..e6ee77cb62bb6 100644 --- a/src/test/run-pass/fn-bare-spawn.rs +++ b/src/test/run-pass/fn-bare-spawn.rs @@ -10,7 +10,6 @@ // This is what the signature to spawn should look like with bare functions -// pretty-expanded FIXME #23616 fn spawn(val: T, f: fn(T)) { f(val); diff --git a/src/test/run-pass/fn-item-type-cast.rs b/src/test/run-pass/fn-item-type-cast.rs index f8b1582c51577..9a8a8d4782ed5 100644 --- a/src/test/run-pass/fn-item-type-cast.rs +++ b/src/test/run-pass/fn-item-type-cast.rs @@ -10,7 +10,6 @@ // Test explicit coercions from a fn item type to a fn pointer type. -// pretty-expanded FIXME #23616 fn foo(x: isize) -> isize { x * 2 } fn bar(x: isize) -> isize { x * 4 } diff --git a/src/test/run-pass/fn-pattern-expected-type.rs b/src/test/run-pass/fn-pattern-expected-type.rs index 352d0b13c6407..2e9607602fd62 100644 --- a/src/test/run-pass/fn-pattern-expected-type.rs +++ b/src/test/run-pass/fn-pattern-expected-type.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let f = |(x, y): (isize, isize)| { diff --git a/src/test/run-pass/for-destruct.rs b/src/test/run-pass/for-destruct.rs index 9d8c432e98209..963d34a2d2fbd 100644 --- a/src/test/run-pass/for-destruct.rs +++ b/src/test/run-pass/for-destruct.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Pair { x: isize, y: isize } diff --git a/src/test/run-pass/for-loop-goofiness.rs b/src/test/run-pass/for-loop-goofiness.rs index 4b6b6dcf1d555..411183e4f74a7 100644 --- a/src/test/run-pass/for-loop-goofiness.rs +++ b/src/test/run-pass/for-loop-goofiness.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum BogusOption { None, diff --git a/src/test/run-pass/for-loop-into-iterator.rs b/src/test/run-pass/for-loop-into-iterator.rs index 109ca26056fff..7efd15f222e37 100644 --- a/src/test/run-pass/for-loop-into-iterator.rs +++ b/src/test/run-pass/for-loop-into-iterator.rs @@ -10,7 +10,6 @@ // Test that for loops can do what RFC #235 claims -// pretty-expanded FIXME #23616 fn main() { let mut v = vec![1]; diff --git a/src/test/run-pass/for-loop-panic.rs b/src/test/run-pass/for-loop-panic.rs index 908932fe396be..001ca1a02f632 100644 --- a/src/test/run-pass/for-loop-panic.rs +++ b/src/test/run-pass/for-loop-panic.rs @@ -9,6 +9,5 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x: Vec = Vec::new(); for _ in &x { panic!("moop"); } } diff --git a/src/test/run-pass/foreach-external-iterators-break.rs b/src/test/run-pass/foreach-external-iterators-break.rs index bc041259895f9..bfc0d6cf9d542 100644 --- a/src/test/run-pass/foreach-external-iterators-break.rs +++ b/src/test/run-pass/foreach-external-iterators-break.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = [1; 100]; diff --git a/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs b/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs index cc02ee1459b5e..cedb960143146 100644 --- a/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs +++ b/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections)] diff --git a/src/test/run-pass/foreach-external-iterators-hashmap.rs b/src/test/run-pass/foreach-external-iterators-hashmap.rs index 065e4cfb7682b..79304fce5c166 100644 --- a/src/test/run-pass/foreach-external-iterators-hashmap.rs +++ b/src/test/run-pass/foreach-external-iterators-hashmap.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections)] diff --git a/src/test/run-pass/foreach-external-iterators-loop.rs b/src/test/run-pass/foreach-external-iterators-loop.rs index 60cfc9be0787a..7248537d6a1b6 100644 --- a/src/test/run-pass/foreach-external-iterators-loop.rs +++ b/src/test/run-pass/foreach-external-iterators-loop.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = [1; 100]; diff --git a/src/test/run-pass/foreach-external-iterators-nested.rs b/src/test/run-pass/foreach-external-iterators-nested.rs index a075c08b737e0..87aa3d84003c5 100644 --- a/src/test/run-pass/foreach-external-iterators-nested.rs +++ b/src/test/run-pass/foreach-external-iterators-nested.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = [1; 100]; diff --git a/src/test/run-pass/foreach-external-iterators.rs b/src/test/run-pass/foreach-external-iterators.rs index 2248132d828d1..d1fe98f5431f7 100644 --- a/src/test/run-pass/foreach-external-iterators.rs +++ b/src/test/run-pass/foreach-external-iterators.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = [1; 100]; diff --git a/src/test/run-pass/foreach-nested.rs b/src/test/run-pass/foreach-nested.rs index 075539b621ac7..60068185f5a52 100644 --- a/src/test/run-pass/foreach-nested.rs +++ b/src/test/run-pass/foreach-nested.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn two(mut it: F) where F: FnMut(isize) { it(0); it(1); } diff --git a/src/test/run-pass/foreign-fn-with-byval.rs b/src/test/run-pass/foreign-fn-with-byval.rs index 7883c22f909dd..d3d872620c38b 100644 --- a/src/test/run-pass/foreign-fn-with-byval.rs +++ b/src/test/run-pass/foreign-fn-with-byval.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] pub struct S { diff --git a/src/test/run-pass/format-nan.rs b/src/test/run-pass/format-nan.rs index bdbbeaa9511cd..9bbd8cdb11d88 100644 --- a/src/test/run-pass/format-nan.rs +++ b/src/test/run-pass/format-nan.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { use std::f64; diff --git a/src/test/run-pass/format-ref-cell.rs b/src/test/run-pass/format-ref-cell.rs index ce26fbd4c00f9..0f16dfa1e8f15 100644 --- a/src/test/run-pass/format-ref-cell.rs +++ b/src/test/run-pass/format-ref-cell.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::cell::RefCell; diff --git a/src/test/run-pass/fsu-moves-and-copies.rs b/src/test/run-pass/fsu-moves-and-copies.rs index fecaf279d043d..dd58787a1de90 100644 --- a/src/test/run-pass/fsu-moves-and-copies.rs +++ b/src/test/run-pass/fsu-moves-and-copies.rs @@ -11,7 +11,6 @@ // Issue 4691: Ensure that functional-struct-updates operates // correctly and moves rather than copy when appropriate. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, core)] diff --git a/src/test/run-pass/fun-call-variants.rs b/src/test/run-pass/fun-call-variants.rs index 0fe4bbcb7a228..3bb6df33f70a0 100644 --- a/src/test/run-pass/fun-call-variants.rs +++ b/src/test/run-pass/fun-call-variants.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn ho(f: F) -> isize where F: FnOnce(isize) -> isize { let n: isize = f(3); return n; } diff --git a/src/test/run-pass/fun-indirect-call.rs b/src/test/run-pass/fun-indirect-call.rs index 48dfcb73da45c..b28c64d06be2f 100644 --- a/src/test/run-pass/fun-indirect-call.rs +++ b/src/test/run-pass/fun-indirect-call.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 fn f() -> isize { return 42; } diff --git a/src/test/run-pass/func-arg-incomplete-pattern.rs b/src/test/run-pass/func-arg-incomplete-pattern.rs index 2833723708523..6030da44e4ade 100644 --- a/src/test/run-pass/func-arg-incomplete-pattern.rs +++ b/src/test/run-pass/func-arg-incomplete-pattern.rs @@ -11,7 +11,6 @@ // Test that we do not leak when the arg pattern must drop part of the // argument (in this case, the `y` field). -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/func-arg-ref-pattern.rs b/src/test/run-pass/func-arg-ref-pattern.rs index fcc00afb00bdb..ab565e7abcace 100644 --- a/src/test/run-pass/func-arg-ref-pattern.rs +++ b/src/test/run-pass/func-arg-ref-pattern.rs @@ -14,7 +14,6 @@ // boxes. Make sure that we don't free the box as we match the // pattern. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_patterns)] diff --git a/src/test/run-pass/func-arg-wild-pattern.rs b/src/test/run-pass/func-arg-wild-pattern.rs index 4f74ca0ff7215..3ab3ee4db2d5b 100644 --- a/src/test/run-pass/func-arg-wild-pattern.rs +++ b/src/test/run-pass/func-arg-wild-pattern.rs @@ -11,7 +11,6 @@ // Test that we can compile code that uses a `_` in function argument // patterns. -// pretty-expanded FIXME #23616 fn foo((x, _): (isize, isize)) -> isize { x diff --git a/src/test/run-pass/generic-exterior-unique.rs b/src/test/run-pass/generic-exterior-unique.rs index 0e3ce3869bf7b..8dbe6de838869 100644 --- a/src/test/run-pass/generic-exterior-unique.rs +++ b/src/test/run-pass/generic-exterior-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/generic-extern-mangle.rs b/src/test/run-pass/generic-extern-mangle.rs index 7a765703e23a0..67aea1f9f8ae8 100644 --- a/src/test/run-pass/generic-extern-mangle.rs +++ b/src/test/run-pass/generic-extern-mangle.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/generic-fn-infer.rs b/src/test/run-pass/generic-fn-infer.rs index e01f507372216..181e05183d2ec 100644 --- a/src/test/run-pass/generic-fn-infer.rs +++ b/src/test/run-pass/generic-fn-infer.rs @@ -13,7 +13,6 @@ // Issue #45: infer type parameters in function applications -// pretty-expanded FIXME #23616 fn id(x: T) -> T { return x; } diff --git a/src/test/run-pass/generic-object.rs b/src/test/run-pass/generic-object.rs index 44b32f62f9227..0a59a925a5ff6 100644 --- a/src/test/run-pass/generic-object.rs +++ b/src/test/run-pass/generic-object.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/generic-static-methods.rs b/src/test/run-pass/generic-static-methods.rs index 49f8d6a3adb52..7a496ebf8ce34 100644 --- a/src/test/run-pass/generic-static-methods.rs +++ b/src/test/run-pass/generic-static-methods.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait vec_utils { fn map_(x: &Self, f: F) -> Vec where F: FnMut(&T) -> U; diff --git a/src/test/run-pass/generic-type.rs b/src/test/run-pass/generic-type.rs index 73fc3a0d80236..8e7a3add34349 100644 --- a/src/test/run-pass/generic-type.rs +++ b/src/test/run-pass/generic-type.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 struct Pair {x: T, y: T} diff --git a/src/test/run-pass/generic-unique.rs b/src/test/run-pass/generic-unique.rs index 9cf98364eb993..21e9a9a80d0ae 100644 --- a/src/test/run-pass/generic-unique.rs +++ b/src/test/run-pass/generic-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/getopts_ref.rs b/src/test/run-pass/getopts_ref.rs index 52b06ab2928af..c9595d09e21b2 100644 --- a/src/test/run-pass/getopts_ref.rs +++ b/src/test/run-pass/getopts_ref.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(rustc_private)] diff --git a/src/test/run-pass/global-scope.rs b/src/test/run-pass/global-scope.rs index 64d9368a88be8..13da404c253b3 100644 --- a/src/test/run-pass/global-scope.rs +++ b/src/test/run-pass/global-scope.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn f() -> isize { return 1; } diff --git a/src/test/run-pass/guards-not-exhaustive.rs b/src/test/run-pass/guards-not-exhaustive.rs index f5f80914937d3..53c3eff5b81ee 100644 --- a/src/test/run-pass/guards-not-exhaustive.rs +++ b/src/test/run-pass/guards-not-exhaustive.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] enum Q { R(Option) } diff --git a/src/test/run-pass/guards.rs b/src/test/run-pass/guards.rs index 11c67b8af8107..d79dbabac2d42 100644 --- a/src/test/run-pass/guards.rs +++ b/src/test/run-pass/guards.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] struct Pair { x: isize, y: isize } diff --git a/src/test/run-pass/hrtb-fn-like-trait-object.rs b/src/test/run-pass/hrtb-fn-like-trait-object.rs index 858179fb5fe76..8e2e21bed0a7c 100644 --- a/src/test/run-pass/hrtb-fn-like-trait-object.rs +++ b/src/test/run-pass/hrtb-fn-like-trait-object.rs @@ -10,7 +10,6 @@ // A basic test of using a higher-ranked trait bound. -// pretty-expanded FIXME #23616 trait FnLike { fn call(&self, arg: A) -> R; diff --git a/src/test/run-pass/hrtb-fn-like-trait.rs b/src/test/run-pass/hrtb-fn-like-trait.rs index 8b4c2aec8452b..71e314b513251 100644 --- a/src/test/run-pass/hrtb-fn-like-trait.rs +++ b/src/test/run-pass/hrtb-fn-like-trait.rs @@ -10,7 +10,6 @@ // A basic test of using a higher-ranked trait bound. -// pretty-expanded FIXME #23616 trait FnLike { fn call(&self, arg: A) -> R; diff --git a/src/test/run-pass/hrtb-trait-object-paren-notation.rs b/src/test/run-pass/hrtb-trait-object-paren-notation.rs index 7741f1904f6ab..fefbd00476689 100644 --- a/src/test/run-pass/hrtb-trait-object-paren-notation.rs +++ b/src/test/run-pass/hrtb-trait-object-paren-notation.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/huge-largest-array.rs b/src/test/run-pass/huge-largest-array.rs index 2345bb01d8ae9..f0bb31b8470f1 100644 --- a/src/test/run-pass/huge-largest-array.rs +++ b/src/test/run-pass/huge-largest-array.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::size_of; diff --git a/src/test/run-pass/hygiene-dodging-1.rs b/src/test/run-pass/hygiene-dodging-1.rs index e5acc4a2edd68..83f09850f7776 100644 --- a/src/test/run-pass/hygiene-dodging-1.rs +++ b/src/test/run-pass/hygiene-dodging-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod x { pub fn g() -> usize {14} diff --git a/src/test/run-pass/hygienic-labels.rs b/src/test/run-pass/hygienic-labels.rs index 2d530275ea21f..df72a5410a2b2 100644 --- a/src/test/run-pass/hygienic-labels.rs +++ b/src/test/run-pass/hygienic-labels.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! loop_x { ($e: expr) => { diff --git a/src/test/run-pass/i32-sub.rs b/src/test/run-pass/i32-sub.rs index 2cc4e880bbf5e..075faba2fcb85 100644 --- a/src/test/run-pass/i32-sub.rs +++ b/src/test/run-pass/i32-sub.rs @@ -11,6 +11,5 @@ -// pretty-expanded FIXME #23616 pub fn main() { let mut x: i32 = -400; x = 0 - x; assert!((x == 400)); } diff --git a/src/test/run-pass/i8-incr.rs b/src/test/run-pass/i8-incr.rs index 5dd53a268b135..242cea264afb1 100644 --- a/src/test/run-pass/i8-incr.rs +++ b/src/test/run-pass/i8-incr.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let mut x: i8 = -12; diff --git a/src/test/run-pass/if-let.rs b/src/test/run-pass/if-let.rs index c41d02f9b3365..13134abd8fdd9 100644 --- a/src/test/run-pass/if-let.rs +++ b/src/test/run-pass/if-let.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = Some(3); diff --git a/src/test/run-pass/impl-inherent-non-conflict.rs b/src/test/run-pass/impl-inherent-non-conflict.rs index 210bc34bcd1db..0d43f1ca70669 100644 --- a/src/test/run-pass/impl-inherent-non-conflict.rs +++ b/src/test/run-pass/impl-inherent-non-conflict.rs @@ -12,7 +12,6 @@ // with the same name, which can be called on values that have a // precise enough type to allow distinguishing between the methods. -// pretty-expanded FIXME #23616 struct Foo(T); diff --git a/src/test/run-pass/impl-inherent-prefer-over-trait.rs b/src/test/run-pass/impl-inherent-prefer-over-trait.rs index 26f12e9730b2a..f0195976aa832 100644 --- a/src/test/run-pass/impl-inherent-prefer-over-trait.rs +++ b/src/test/run-pass/impl-inherent-prefer-over-trait.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Foo; diff --git a/src/test/run-pass/impl-not-adjacent-to-type.rs b/src/test/run-pass/impl-not-adjacent-to-type.rs index 2ba7375d67a64..beba056b72cdc 100644 --- a/src/test/run-pass/impl-not-adjacent-to-type.rs +++ b/src/test/run-pass/impl-not-adjacent-to-type.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod foo { pub struct Point { diff --git a/src/test/run-pass/import-glob-crate.rs b/src/test/run-pass/import-glob-crate.rs index eb9ec6fe985ac..b2a9b08b01b86 100644 --- a/src/test/run-pass/import-glob-crate.rs +++ b/src/test/run-pass/import-glob-crate.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(dead_assignment)] diff --git a/src/test/run-pass/inferred-suffix-in-pattern-range.rs b/src/test/run-pass/inferred-suffix-in-pattern-range.rs index fcbd4b332318e..22369c77ed33f 100644 --- a/src/test/run-pass/inferred-suffix-in-pattern-range.rs +++ b/src/test/run-pass/inferred-suffix-in-pattern-range.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = 2; diff --git a/src/test/run-pass/inherent-trait-method-order.rs b/src/test/run-pass/inherent-trait-method-order.rs index 042268435c7af..5489a61f7d0b9 100644 --- a/src/test/run-pass/inherent-trait-method-order.rs +++ b/src/test/run-pass/inherent-trait-method-order.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Foo; diff --git a/src/test/run-pass/init-res-into-things.rs b/src/test/run-pass/init-res-into-things.rs index eb50fbed774e4..97b32189d0027 100644 --- a/src/test/run-pass/init-res-into-things.rs +++ b/src/test/run-pass/init-res-into-things.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/inner-attrs-on-impl.rs b/src/test/run-pass/inner-attrs-on-impl.rs index a807e582ff464..d8d9d5136e2d1 100644 --- a/src/test/run-pass/inner-attrs-on-impl.rs +++ b/src/test/run-pass/inner-attrs-on-impl.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 struct Foo; diff --git a/src/test/run-pass/inner-static.rs b/src/test/run-pass/inner-static.rs index 48f2006ed59ba..b93ca943e4714 100644 --- a/src/test/run-pass/inner-static.rs +++ b/src/test/run-pass/inner-static.rs @@ -10,7 +10,6 @@ // aux-build:inner_static.rs -// pretty-expanded FIXME #23616 extern crate inner_static; diff --git a/src/test/run-pass/integer-literal-radix.rs b/src/test/run-pass/integer-literal-radix.rs index b782925fa9357..ba9d22f06a976 100644 --- a/src/test/run-pass/integer-literal-radix.rs +++ b/src/test/run-pass/integer-literal-radix.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let a = 0xBEEF_isize; diff --git a/src/test/run-pass/intrinsic-alignment.rs b/src/test/run-pass/intrinsic-alignment.rs index 44dd191eb3ee3..fa97ef8fcd394 100644 --- a/src/test/run-pass/intrinsic-alignment.rs +++ b/src/test/run-pass/intrinsic-alignment.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(intrinsics, main)] diff --git a/src/test/run-pass/intrinsic-assume.rs b/src/test/run-pass/intrinsic-assume.rs index fc886d7e30165..ff7d799f64c5f 100644 --- a/src/test/run-pass/intrinsic-assume.rs +++ b/src/test/run-pass/intrinsic-assume.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/intrinsic-atomics-cc.rs b/src/test/run-pass/intrinsic-atomics-cc.rs index c5fe02b9190d4..abb85cc7f1949 100644 --- a/src/test/run-pass/intrinsic-atomics-cc.rs +++ b/src/test/run-pass/intrinsic-atomics-cc.rs @@ -10,7 +10,6 @@ // aux-build:cci_intrinsic.rs -// pretty-expanded FIXME #23616 extern crate cci_intrinsic; use cci_intrinsic::atomic_xchg; diff --git a/src/test/run-pass/intrinsic-atomics.rs b/src/test/run-pass/intrinsic-atomics.rs index 61a9f6109a3e8..4ccab55e94348 100644 --- a/src/test/run-pass/intrinsic-atomics.rs +++ b/src/test/run-pass/intrinsic-atomics.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/intrinsic-move-val.rs b/src/test/run-pass/intrinsic-move-val.rs index 98f069f77f3f0..2e75f2dccd1ba 100644 --- a/src/test/run-pass/intrinsic-move-val.rs +++ b/src/test/run-pass/intrinsic-move-val.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/intrinsic-return-address.rs b/src/test/run-pass/intrinsic-return-address.rs index 1ff910356eb98..63aed3f009fd7 100644 --- a/src/test/run-pass/intrinsic-return-address.rs +++ b/src/test/run-pass/intrinsic-return-address.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(intrinsics)] diff --git a/src/test/run-pass/intrinsic-unreachable.rs b/src/test/run-pass/intrinsic-unreachable.rs index 86a370a0942d9..a86fc110ae4eb 100644 --- a/src/test/run-pass/intrinsic-unreachable.rs +++ b/src/test/run-pass/intrinsic-unreachable.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs index 15dbe796ef589..f1d731c8b1d7a 100644 --- a/src/test/run-pass/intrinsics-integer.rs +++ b/src/test/run-pass/intrinsics-integer.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(negate_unsigned)] #![feature(intrinsics)] diff --git a/src/test/run-pass/intrinsics-math.rs b/src/test/run-pass/intrinsics-math.rs index 841ff297a2ac7..8db29ebaa6d3e 100644 --- a/src/test/run-pass/intrinsics-math.rs +++ b/src/test/run-pass/intrinsics-math.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(intrinsics, core)] diff --git a/src/test/run-pass/issue-10392.rs b/src/test/run-pass/issue-10392.rs index 2d695c75d3044..1a5f423b0fd8b 100644 --- a/src/test/run-pass/issue-10392.rs +++ b/src/test/run-pass/issue-10392.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct A { foo: isize } struct B { a: isize, b: isize, c: isize } diff --git a/src/test/run-pass/issue-10734.rs b/src/test/run-pass/issue-10734.rs index 49694f2755c23..c99cad85ccb39 100644 --- a/src/test/run-pass/issue-10734.rs +++ b/src/test/run-pass/issue-10734.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_no_drop_flag)] diff --git a/src/test/run-pass/issue-10802.rs b/src/test/run-pass/issue-10802.rs index bb322635094e5..2256315a379ae 100644 --- a/src/test/run-pass/issue-10802.rs +++ b/src/test/run-pass/issue-10802.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/issue-1112.rs b/src/test/run-pass/issue-1112.rs index 3d131b51033dc..72d1a43e88318 100644 --- a/src/test/run-pass/issue-1112.rs +++ b/src/test/run-pass/issue-1112.rs @@ -11,7 +11,6 @@ // Issue #1112 // Alignment of interior pointers to dynamic-size types -// pretty-expanded FIXME #23616 struct X { a: T, diff --git a/src/test/run-pass/issue-11552.rs b/src/test/run-pass/issue-11552.rs index 1f91c6aaa4d0a..5193330a45a36 100644 --- a/src/test/run-pass/issue-11552.rs +++ b/src/test/run-pass/issue-11552.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_patterns)] diff --git a/src/test/run-pass/issue-11577.rs b/src/test/run-pass/issue-11577.rs index ecb7a3a3691ca..81588e8ef78db 100644 --- a/src/test/run-pass/issue-11577.rs +++ b/src/test/run-pass/issue-11577.rs @@ -1,4 +1,3 @@ -// pretty-expanded FIXME #23616 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at diff --git a/src/test/run-pass/issue-11677.rs b/src/test/run-pass/issue-11677.rs index a3eec42831f20..d4244d44439b0 100644 --- a/src/test/run-pass/issue-11677.rs +++ b/src/test/run-pass/issue-11677.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(dead_code)] diff --git a/src/test/run-pass/issue-11940.rs b/src/test/run-pass/issue-11940.rs index 8732def0a1a11..186446a345677 100644 --- a/src/test/run-pass/issue-11940.rs +++ b/src/test/run-pass/issue-11940.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const TEST_STR: &'static str = "abcd"; diff --git a/src/test/run-pass/issue-12285.rs b/src/test/run-pass/issue-12285.rs index 3a5b7e86920d7..fb98909eb9765 100644 --- a/src/test/run-pass/issue-12285.rs +++ b/src/test/run-pass/issue-12285.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct S; diff --git a/src/test/run-pass/issue-12677.rs b/src/test/run-pass/issue-12677.rs index 493bdb30e35bc..e83a2e9727d99 100644 --- a/src/test/run-pass/issue-12677.rs +++ b/src/test/run-pass/issue-12677.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { let s = "Hello"; diff --git a/src/test/run-pass/issue-13204.rs b/src/test/run-pass/issue-13204.rs index ec9d777974bb0..36f606e5d73c9 100644 --- a/src/test/run-pass/issue-13204.rs +++ b/src/test/run-pass/issue-13204.rs @@ -11,7 +11,6 @@ // Test that when instantiating trait default methods, typeck handles // lifetime parameters defined on the method bound correctly. -// pretty-expanded FIXME #23616 pub trait Foo { fn bar<'a, I: Iterator>(&self, it: I) -> usize { diff --git a/src/test/run-pass/issue-13323.rs b/src/test/run-pass/issue-13323.rs index 90d16aaf145af..68c6ce7a7b7ba 100644 --- a/src/test/run-pass/issue-13323.rs +++ b/src/test/run-pass/issue-13323.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/issue-13507-2.rs b/src/test/run-pass/issue-13507-2.rs index 0b35ccf26f3f7..91ec3e8540442 100644 --- a/src/test/run-pass/issue-13507-2.rs +++ b/src/test/run-pass/issue-13507-2.rs @@ -10,7 +10,6 @@ // aux-build:issue13507.rs -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/issue-13867.rs b/src/test/run-pass/issue-13867.rs index a902e141bb6ca..e21070e2eafa1 100644 --- a/src/test/run-pass/issue-13867.rs +++ b/src/test/run-pass/issue-13867.rs @@ -11,7 +11,6 @@ // Test that codegen works correctly when there are multiple refutable // patterns in match expression. -// pretty-expanded FIXME #23616 enum Foo { FooUint(usize), diff --git a/src/test/run-pass/issue-14308.rs b/src/test/run-pass/issue-14308.rs index f67d0946e9823..a61cb18faa65a 100644 --- a/src/test/run-pass/issue-14308.rs +++ b/src/test/run-pass/issue-14308.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct A(isize); struct B; diff --git a/src/test/run-pass/issue-14456.rs b/src/test/run-pass/issue-14456.rs index ab9633ca1fe90..7e24c8f73ab70 100644 --- a/src/test/run-pass/issue-14456.rs +++ b/src/test/run-pass/issue-14456.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(io, process_capture)] diff --git a/src/test/run-pass/issue-14865.rs b/src/test/run-pass/issue-14865.rs index e78736b77fd93..1ec268bb17037 100644 --- a/src/test/run-pass/issue-14865.rs +++ b/src/test/run-pass/issue-14865.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum X { Foo(usize), diff --git a/src/test/run-pass/issue-14936.rs b/src/test/run-pass/issue-14936.rs index 2361c385b4148..5f8e7cb8145e6 100644 --- a/src/test/run-pass/issue-14936.rs +++ b/src/test/run-pass/issue-14936.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(asm)] diff --git a/src/test/run-pass/issue-14940.rs b/src/test/run-pass/issue-14940.rs index a530384d368c0..b51afc1d02095 100644 --- a/src/test/run-pass/issue-14940.rs +++ b/src/test/run-pass/issue-14940.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(old_io, io)] diff --git a/src/test/run-pass/issue-15080.rs b/src/test/run-pass/issue-15080.rs index 4369dc6292c36..ecb83cca6f273 100644 --- a/src/test/run-pass/issue-15080.rs +++ b/src/test/run-pass/issue-15080.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-pass/issue-15104.rs b/src/test/run-pass/issue-15104.rs index db04e10cfe383..b55754ee59b35 100644 --- a/src/test/run-pass/issue-15104.rs +++ b/src/test/run-pass/issue-15104.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-pass/issue-15129.rs b/src/test/run-pass/issue-15129.rs index 54705c6bf1301..9bcfa6ea40a4e 100644 --- a/src/test/run-pass/issue-15129.rs +++ b/src/test/run-pass/issue-15129.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub enum T { T1(()), diff --git a/src/test/run-pass/issue-15149.rs b/src/test/run-pass/issue-15149.rs index ee348d9cb0ccf..f6ffd03c81aee 100644 --- a/src/test/run-pass/issue-15149.rs +++ b/src/test/run-pass/issue-15149.rs @@ -10,7 +10,6 @@ // no-prefer-dynamic -// pretty-expanded FIXME #23616 #![feature(fs, process, env, path, rand)] diff --git a/src/test/run-pass/issue-15673.rs b/src/test/run-pass/issue-15673.rs index c1ecd3eba48bd..c478ca041148a 100644 --- a/src/test/run-pass/issue-15673.rs +++ b/src/test/run-pass/issue-15673.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/issue-15689-1.rs b/src/test/run-pass/issue-15689-1.rs index 9fc1cce56b767..e3c16793c19cb 100644 --- a/src/test/run-pass/issue-15689-1.rs +++ b/src/test/run-pass/issue-15689-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(PartialEq)] enum Test<'a> { diff --git a/src/test/run-pass/issue-15734.rs b/src/test/run-pass/issue-15734.rs index 67ce6a1c44f0d..7f44c5a84cbaf 100644 --- a/src/test/run-pass/issue-15734.rs +++ b/src/test/run-pass/issue-15734.rs @@ -11,7 +11,6 @@ // If `Index` used an associated type for its output, this test would // work more smoothly. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/issue-15793.rs b/src/test/run-pass/issue-15793.rs index 21baf47ee6610..432174a1f52a0 100644 --- a/src/test/run-pass/issue-15793.rs +++ b/src/test/run-pass/issue-15793.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum NestedEnum { First, diff --git a/src/test/run-pass/issue-15858.rs b/src/test/run-pass/issue-15858.rs index 265db3fe1336a..4f084d7891f37 100644 --- a/src/test/run-pass/issue-15858.rs +++ b/src/test/run-pass/issue-15858.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/issue-15881-model-lexer-dotdotdot.rs b/src/test/run-pass/issue-15881-model-lexer-dotdotdot.rs index 6b75e4e47978e..2ec97e373b29b 100644 --- a/src/test/run-pass/issue-15881-model-lexer-dotdotdot.rs +++ b/src/test/run-pass/issue-15881-model-lexer-dotdotdot.rs @@ -10,7 +10,6 @@ // // regression test for the model lexer handling the DOTDOTDOT syntax (#15877) -// pretty-expanded FIXME #23616 pub fn main() { match 5_usize { diff --git a/src/test/run-pass/issue-16151.rs b/src/test/run-pass/issue-16151.rs index 242bcb69be60d..212dfaf3cb6c7 100644 --- a/src/test/run-pass/issue-16151.rs +++ b/src/test/run-pass/issue-16151.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/issue-16530.rs b/src/test/run-pass/issue-16530.rs index bf33221431ae0..77ec44161ea72 100644 --- a/src/test/run-pass/issue-16530.rs +++ b/src/test/run-pass/issue-16530.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(hash)] diff --git a/src/test/run-pass/issue-16560.rs b/src/test/run-pass/issue-16560.rs index 33842fab6989c..a9f7d86f95ee6 100644 --- a/src/test/run-pass/issue-16560.rs +++ b/src/test/run-pass/issue-16560.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/issue-16596.rs b/src/test/run-pass/issue-16596.rs index 743dbbc9b9956..d70158743e720 100644 --- a/src/test/run-pass/issue-16596.rs +++ b/src/test/run-pass/issue-16596.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait MatrixRow { fn dummy(&self) { }} diff --git a/src/test/run-pass/issue-16648.rs b/src/test/run-pass/issue-16648.rs index f0ff9ce7554b5..384bd9df7cfed 100644 --- a/src/test/run-pass/issue-16648.rs +++ b/src/test/run-pass/issue-16648.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-pass/issue-16739.rs b/src/test/run-pass/issue-16739.rs index 99ddaba4e5514..f8cffdd38ca9b 100644 --- a/src/test/run-pass/issue-16739.rs +++ b/src/test/run-pass/issue-16739.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/issue-16774.rs b/src/test/run-pass/issue-16774.rs index 17d0969ce1c02..627717ab1cd14 100644 --- a/src/test/run-pass/issue-16774.rs +++ b/src/test/run-pass/issue-16774.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/issue-1701.rs b/src/test/run-pass/issue-1701.rs index b8c51f2cd3112..3a2e46c62b079 100644 --- a/src/test/run-pass/issue-1701.rs +++ b/src/test/run-pass/issue-1701.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum pattern { tabby, tortoiseshell, calico } enum breed { beagle, rottweiler, pug } diff --git a/src/test/run-pass/issue-17068.rs b/src/test/run-pass/issue-17068.rs index 55a6d4cdbace7..91264b4ac3f2b 100644 --- a/src/test/run-pass/issue-17068.rs +++ b/src/test/run-pass/issue-17068.rs @@ -10,7 +10,6 @@ // Test that regionck creates the right region links in the pattern // binding of a for loop -// pretty-expanded FIXME #23616 fn foo<'a>(v: &'a [usize]) -> &'a usize { for &ref x in v { return x; } diff --git a/src/test/run-pass/issue-17074.rs b/src/test/run-pass/issue-17074.rs index 08c313ab0a42b..ec2d8f79781cc 100644 --- a/src/test/run-pass/issue-17074.rs +++ b/src/test/run-pass/issue-17074.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 static X2: u64 = !0 as u16 as u64; static Y2: u64 = !0 as u32 as u64; diff --git a/src/test/run-pass/issue-17216.rs b/src/test/run-pass/issue-17216.rs index f17834e8d36dc..6a8f7d992a292 100644 --- a/src/test/run-pass/issue-17216.rs +++ b/src/test/run-pass/issue-17216.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/issue-17233.rs b/src/test/run-pass/issue-17233.rs index 756822d4f45fa..e9f0c73e29db3 100644 --- a/src/test/run-pass/issue-17233.rs +++ b/src/test/run-pass/issue-17233.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const X1: &'static [u8] = &[b'1']; const X2: &'static [u8] = b"1"; diff --git a/src/test/run-pass/issue-17302.rs b/src/test/run-pass/issue-17302.rs index 35bd07c896bb6..59625581167d0 100644 --- a/src/test/run-pass/issue-17302.rs +++ b/src/test/run-pass/issue-17302.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 static mut DROPPED: [bool; 2] = [false, false]; diff --git a/src/test/run-pass/issue-17662.rs b/src/test/run-pass/issue-17662.rs index 36e12b96c8744..320d108cfae74 100644 --- a/src/test/run-pass/issue-17662.rs +++ b/src/test/run-pass/issue-17662.rs @@ -10,7 +10,6 @@ // aux-build:issue-17662.rs -// pretty-expanded FIXME #23616 extern crate issue_17662 as i; diff --git a/src/test/run-pass/issue-17718-parse-const.rs b/src/test/run-pass/issue-17718-parse-const.rs index 1fc8f3274d459..9be92d6597850 100644 --- a/src/test/run-pass/issue-17718-parse-const.rs +++ b/src/test/run-pass/issue-17718-parse-const.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const FOO: usize = 3; diff --git a/src/test/run-pass/issue-17718.rs b/src/test/run-pass/issue-17718.rs index 13e082eada884..2b84ce71dd2a2 100644 --- a/src/test/run-pass/issue-17718.rs +++ b/src/test/run-pass/issue-17718.rs @@ -10,7 +10,6 @@ // aux-build:issue-17718.rs -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/issue-17734.rs b/src/test/run-pass/issue-17734.rs index 3cf9c62b40d49..0fc8eea778da9 100644 --- a/src/test/run-pass/issue-17734.rs +++ b/src/test/run-pass/issue-17734.rs @@ -10,7 +10,6 @@ // Test that generating drop glue for Box doesn't ICE -// pretty-expanded FIXME #23616 fn f(s: Box) -> Box { s diff --git a/src/test/run-pass/issue-17877.rs b/src/test/run-pass/issue-17877.rs index 41fab9d9d54e0..6c87e8d35fbf0 100644 --- a/src/test/run-pass/issue-17877.rs +++ b/src/test/run-pass/issue-17877.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-pass/issue-18352.rs b/src/test/run-pass/issue-18352.rs index 4e60a7d9b5fbb..cce6ba407a663 100644 --- a/src/test/run-pass/issue-18352.rs +++ b/src/test/run-pass/issue-18352.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const X: &'static str = "12345"; diff --git a/src/test/run-pass/issue-18412.rs b/src/test/run-pass/issue-18412.rs index 41dacd3320379..1017fab5ae2e0 100644 --- a/src/test/run-pass/issue-18412.rs +++ b/src/test/run-pass/issue-18412.rs @@ -11,7 +11,6 @@ // Test that non-static methods can be assigned to local variables as // function pointers. -// pretty-expanded FIXME #23616 trait Foo { fn foo(&self) -> usize; diff --git a/src/test/run-pass/issue-18652.rs b/src/test/run-pass/issue-18652.rs index a3affb7bf86f0..8ab645e54addc 100644 --- a/src/test/run-pass/issue-18652.rs +++ b/src/test/run-pass/issue-18652.rs @@ -12,7 +12,6 @@ // once closure as an optimization by trans. This used to hit an // incorrect assert. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/issue-18767.rs b/src/test/run-pass/issue-18767.rs index 8e51a900c0cae..264985b791e7f 100644 --- a/src/test/run-pass/issue-18767.rs +++ b/src/test/run-pass/issue-18767.rs @@ -11,7 +11,6 @@ // Test that regionck uses the right memcat for patterns in for loops // and doesn't ICE. -// pretty-expanded FIXME #23616 fn main() { for &&x in Some(&0_usize).iter() { diff --git a/src/test/run-pass/issue-18859.rs b/src/test/run-pass/issue-18859.rs index 16e6c99f0e31d..7c7501d3420d2 100644 --- a/src/test/run-pass/issue-18859.rs +++ b/src/test/run-pass/issue-18859.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod foo { pub mod bar { diff --git a/src/test/run-pass/issue-19244.rs b/src/test/run-pass/issue-19244.rs index f25450a891827..92ac2e37b90d2 100644 --- a/src/test/run-pass/issue-19244.rs +++ b/src/test/run-pass/issue-19244.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct MyStruct { field: usize } struct Nested { nested: MyStruct } diff --git a/src/test/run-pass/issue-19811-escape-unicode.rs b/src/test/run-pass/issue-19811-escape-unicode.rs index 5b415c63885e6..e6e9bf6e6367f 100644 --- a/src/test/run-pass/issue-19811-escape-unicode.rs +++ b/src/test/run-pass/issue-19811-escape-unicode.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections)] diff --git a/src/test/run-pass/issue-21058.rs b/src/test/run-pass/issue-21058.rs index d7a656be7afb0..c384757c5e4fb 100644 --- a/src/test/run-pass/issue-21058.rs +++ b/src/test/run-pass/issue-21058.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/issue-21306.rs b/src/test/run-pass/issue-21306.rs index cabda0b500bd5..bc2c7f09374fa 100644 --- a/src/test/run-pass/issue-21306.rs +++ b/src/test/run-pass/issue-21306.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::sync::Arc; diff --git a/src/test/run-pass/issue-21361.rs b/src/test/run-pass/issue-21361.rs index ef86634125ebd..b89e07ef31f0b 100644 --- a/src/test/run-pass/issue-21361.rs +++ b/src/test/run-pass/issue-21361.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { let v = vec![1, 2, 3]; diff --git a/src/test/run-pass/issue-21384.rs b/src/test/run-pass/issue-21384.rs index 41a9ca840b178..e10fcd30b9961 100644 --- a/src/test/run-pass/issue-21384.rs +++ b/src/test/run-pass/issue-21384.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use ::std::ops::RangeFull; diff --git a/src/test/run-pass/issue-21634.rs b/src/test/run-pass/issue-21634.rs index fe540e1aabef8..2a146ae8fcf7b 100644 --- a/src/test/run-pass/issue-21634.rs +++ b/src/test/run-pass/issue-21634.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { if let Ok(x) = "3.1415".parse::() { diff --git a/src/test/run-pass/issue-21655.rs b/src/test/run-pass/issue-21655.rs index cb87770c565c0..bf01873bea5e7 100644 --- a/src/test/run-pass/issue-21655.rs +++ b/src/test/run-pass/issue-21655.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn test(it: &mut Iterator) { for x in it { diff --git a/src/test/run-pass/issue-21721.rs b/src/test/run-pass/issue-21721.rs index c34ab1b0ea7ce..d1fc61ff6a5d4 100644 --- a/src/test/run-pass/issue-21721.rs +++ b/src/test/run-pass/issue-21721.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { static NONE: Option<((), &'static u8)> = None; diff --git a/src/test/run-pass/issue-22036.rs b/src/test/run-pass/issue-22036.rs index e02ce5441a7d4..43fb286f0ec40 100644 --- a/src/test/run-pass/issue-22036.rs +++ b/src/test/run-pass/issue-22036.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait DigitCollection: Sized { type Iter: Iterator; diff --git a/src/test/run-pass/issue-2214.rs b/src/test/run-pass/issue-2214.rs index 38895e1414cee..775cfb0ee4219 100644 --- a/src/test/run-pass/issue-2214.rs +++ b/src/test/run-pass/issue-2214.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(libc)] diff --git a/src/test/run-pass/issue-22536-copy-mustnt-zero.rs b/src/test/run-pass/issue-22536-copy-mustnt-zero.rs index 8a0f04a2cf0e4..af99b11c2534f 100644 --- a/src/test/run-pass/issue-22536-copy-mustnt-zero.rs +++ b/src/test/run-pass/issue-22536-copy-mustnt-zero.rs @@ -11,7 +11,6 @@ // Regression test for Issue #22536: If a type implements Copy, then // moving it must not zero the original memory. -// pretty-expanded FIXME #23616 trait Resources { type Buffer: Copy; diff --git a/src/test/run-pass/issue-2311-2.rs b/src/test/run-pass/issue-2311-2.rs index c76bbaf968a65..a47c151255270 100644 --- a/src/test/run-pass/issue-2311-2.rs +++ b/src/test/run-pass/issue-2311-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait clam { fn get(self) -> A; diff --git a/src/test/run-pass/issue-2312.rs b/src/test/run-pass/issue-2312.rs index fa056191e671e..6f479c621170e 100644 --- a/src/test/run-pass/issue-2312.rs +++ b/src/test/run-pass/issue-2312.rs @@ -10,7 +10,6 @@ // Testing that the B's are resolved -// pretty-expanded FIXME #23616 trait clam { fn get(self) -> A; } diff --git a/src/test/run-pass/issue-2428.rs b/src/test/run-pass/issue-2428.rs index 402eb0349ab23..a07050d4582f0 100644 --- a/src/test/run-pass/issue-2428.rs +++ b/src/test/run-pass/issue-2428.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let _foo = 100; diff --git a/src/test/run-pass/issue-2611-3.rs b/src/test/run-pass/issue-2611-3.rs index 8cf80333e9722..242528dcb1474 100644 --- a/src/test/run-pass/issue-2611-3.rs +++ b/src/test/run-pass/issue-2611-3.rs @@ -11,7 +11,6 @@ // Tests that impls are allowed to have looser, more permissive bounds // than the traits require. -// pretty-expanded FIXME #23616 trait A { fn b(&self, x: C) -> C; diff --git a/src/test/run-pass/issue-2735-2.rs b/src/test/run-pass/issue-2735-2.rs index 1506b2d6bf089..36d7f4583b09f 100644 --- a/src/test/run-pass/issue-2735-2.rs +++ b/src/test/run-pass/issue-2735-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/issue-2735-3.rs b/src/test/run-pass/issue-2735-3.rs index 2282334d66d10..f438519b72f3b 100644 --- a/src/test/run-pass/issue-2735-3.rs +++ b/src/test/run-pass/issue-2735-3.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/issue-2748-b.rs b/src/test/run-pass/issue-2748-b.rs index 8f30d262f41f5..f1cbf11a347eb 100644 --- a/src/test/run-pass/issue-2748-b.rs +++ b/src/test/run-pass/issue-2748-b.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn thing<'r>(x: &'r [isize]) -> &'r [isize] { x } diff --git a/src/test/run-pass/issue-2895.rs b/src/test/run-pass/issue-2895.rs index 3f4c630cc2b0a..93d9300edf634 100644 --- a/src/test/run-pass/issue-2895.rs +++ b/src/test/run-pass/issue-2895.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/issue-2936.rs b/src/test/run-pass/issue-2936.rs index 5c63230f5d0ca..c277073a79dc9 100644 --- a/src/test/run-pass/issue-2936.rs +++ b/src/test/run-pass/issue-2936.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait bar { fn get_bar(&self) -> T; diff --git a/src/test/run-pass/issue-3091.rs b/src/test/run-pass/issue-3091.rs index 8e59e46fc3c4c..c67399a89e9c6 100644 --- a/src/test/run-pass/issue-3091.rs +++ b/src/test/run-pass/issue-3091.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = 1; diff --git a/src/test/run-pass/issue-3290.rs b/src/test/run-pass/issue-3290.rs index 3fa5b72c348f3..b09820146f5b8 100644 --- a/src/test/run-pass/issue-3290.rs +++ b/src/test/run-pass/issue-3290.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/issue-333.rs b/src/test/run-pass/issue-333.rs index b611f11a0a124..592ff0b02a4ad 100644 --- a/src/test/run-pass/issue-333.rs +++ b/src/test/run-pass/issue-333.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn quux(x: T) -> T { let f = id::; return f(x); } diff --git a/src/test/run-pass/issue-3574.rs b/src/test/run-pass/issue-3574.rs index 9a521ba376dc2..9aac52fa2f8a1 100644 --- a/src/test/run-pass/issue-3574.rs +++ b/src/test/run-pass/issue-3574.rs @@ -10,7 +10,6 @@ // rustc --test match_borrowed_str.rs.rs && ./match_borrowed_str.rs -// pretty-expanded FIXME #23616 fn compare(x: &str, y: &str) -> bool { match x { diff --git a/src/test/run-pass/issue-3895.rs b/src/test/run-pass/issue-3895.rs index ca6d9faf88f4a..ffe14dab30039 100644 --- a/src/test/run-pass/issue-3895.rs +++ b/src/test/run-pass/issue-3895.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { enum State { BadChar, BadSyntax } diff --git a/src/test/run-pass/issue-3935.rs b/src/test/run-pass/issue-3935.rs index 1e200e01628a5..45ff20fc0a9c3 100644 --- a/src/test/run-pass/issue-3935.rs +++ b/src/test/run-pass/issue-3935.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(PartialEq)] struct Bike { diff --git a/src/test/run-pass/issue-3979-generics.rs b/src/test/run-pass/issue-3979-generics.rs index 61708acf7f317..6ba566012c3be 100644 --- a/src/test/run-pass/issue-3979-generics.rs +++ b/src/test/run-pass/issue-3979-generics.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::ops::Add; diff --git a/src/test/run-pass/issue-3979-xcrate.rs b/src/test/run-pass/issue-3979-xcrate.rs index 0784877849ad1..acacc48856646 100644 --- a/src/test/run-pass/issue-3979-xcrate.rs +++ b/src/test/run-pass/issue-3979-xcrate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:issue_3979_traits.rs -// pretty-expanded FIXME #23616 extern crate issue_3979_traits; use issue_3979_traits::{Positioned, Movable}; diff --git a/src/test/run-pass/issue-3979.rs b/src/test/run-pass/issue-3979.rs index 341866e4982ff..184682255d936 100644 --- a/src/test/run-pass/issue-3979.rs +++ b/src/test/run-pass/issue-3979.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Positioned { fn SetX(&mut self, isize); diff --git a/src/test/run-pass/issue-4016.rs b/src/test/run-pass/issue-4016.rs index 122de97c99c1c..bc3fa162e02bd 100644 --- a/src/test/run-pass/issue-4016.rs +++ b/src/test/run-pass/issue-4016.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(rustc_private)] diff --git a/src/test/run-pass/issue-4107.rs b/src/test/run-pass/issue-4107.rs index 18025c315c95c..fa5ed26847b57 100644 --- a/src/test/run-pass/issue-4107.rs +++ b/src/test/run-pass/issue-4107.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let _id: &Mat2 = &Matrix::identity(1.0); diff --git a/src/test/run-pass/issue-4448.rs b/src/test/run-pass/issue-4448.rs index d5d3122f6834b..eb411ff441778 100644 --- a/src/test/run-pass/issue-4448.rs +++ b/src/test/run-pass/issue-4448.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::sync::mpsc::channel; use std::thread; diff --git a/src/test/run-pass/issue-4734.rs b/src/test/run-pass/issue-4734.rs index 82925852a6a3d..88a3b24d14fc8 100644 --- a/src/test/run-pass/issue-4734.rs +++ b/src/test/run-pass/issue-4734.rs @@ -11,7 +11,6 @@ // Ensures that destructors are run for expressions of the form "e;" where // `e` is a type which requires a destructor. -// pretty-expanded FIXME #23616 #![allow(path_statement)] diff --git a/src/test/run-pass/issue-5239-2.rs b/src/test/run-pass/issue-5239-2.rs index d8491070bd8b5..5e58d76d5e0ff 100644 --- a/src/test/run-pass/issue-5239-2.rs +++ b/src/test/run-pass/issue-5239-2.rs @@ -10,7 +10,6 @@ // Regression test for issue #5239 -// pretty-expanded FIXME #23616 pub fn main() { let _f = |ref x: isize| { *x }; diff --git a/src/test/run-pass/issue-5521.rs b/src/test/run-pass/issue-5521.rs index 4ad729f1bc60a..136f7aa956c0d 100644 --- a/src/test/run-pass/issue-5521.rs +++ b/src/test/run-pass/issue-5521.rs @@ -11,7 +11,6 @@ // aux-build:issue-5521.rs -// pretty-expanded FIXME #23616 extern crate issue_5521 as foo; diff --git a/src/test/run-pass/issue-5530.rs b/src/test/run-pass/issue-5530.rs index 50b9ca6e797d8..bd7d7af71df85 100644 --- a/src/test/run-pass/issue-5530.rs +++ b/src/test/run-pass/issue-5530.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum Enum { Foo { foo: usize }, diff --git a/src/test/run-pass/issue-5917.rs b/src/test/run-pass/issue-5917.rs index 7f741182f4223..112ad0185d8cb 100644 --- a/src/test/run-pass/issue-5917.rs +++ b/src/test/run-pass/issue-5917.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct T (&'static [isize]); static t : T = T (&[5, 4, 3]); diff --git a/src/test/run-pass/issue-5997.rs b/src/test/run-pass/issue-5997.rs index 48923bc82b4e0..0c41acf04aae6 100644 --- a/src/test/run-pass/issue-5997.rs +++ b/src/test/run-pass/issue-5997.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn f() -> bool { enum E { V(T) } diff --git a/src/test/run-pass/issue-6128.rs b/src/test/run-pass/issue-6128.rs index baf829bc269b6..5fb24fe3ef1ac 100644 --- a/src/test/run-pass/issue-6128.rs +++ b/src/test/run-pass/issue-6128.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, collections)] diff --git a/src/test/run-pass/issue-6130.rs b/src/test/run-pass/issue-6130.rs index 6f158339169cb..f124b851f0925 100644 --- a/src/test/run-pass/issue-6130.rs +++ b/src/test/run-pass/issue-6130.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![deny(type_limits)] diff --git a/src/test/run-pass/issue-6153.rs b/src/test/run-pass/issue-6153.rs index c280ea31ebc47..16e7060f4b9f1 100644 --- a/src/test/run-pass/issue-6153.rs +++ b/src/test/run-pass/issue-6153.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn swap(f: F) -> Vec where F: FnOnce(Vec) -> Vec { let x = vec!(1, 2, 3); diff --git a/src/test/run-pass/issue-6334.rs b/src/test/run-pass/issue-6334.rs index 2f2dca8fe226c..fca1c296dddcc 100644 --- a/src/test/run-pass/issue-6334.rs +++ b/src/test/run-pass/issue-6334.rs @@ -11,7 +11,6 @@ // Tests that everything still compiles and runs fine even when // we reorder the bounds. -// pretty-expanded FIXME #23616 trait A { fn a(&self) -> usize; diff --git a/src/test/run-pass/issue-6449.rs b/src/test/run-pass/issue-6449.rs index 3b33a0ac86f69..09a4e288404f2 100644 --- a/src/test/run-pass/issue-6449.rs +++ b/src/test/run-pass/issue-6449.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum Foo { Bar(isize), diff --git a/src/test/run-pass/issue-6892.rs b/src/test/run-pass/issue-6892.rs index 4469dcc0ced81..75420ad6ff1c5 100644 --- a/src/test/run-pass/issue-6892.rs +++ b/src/test/run-pass/issue-6892.rs @@ -11,7 +11,6 @@ // Ensures that destructors are run for expressions of the form "let _ = e;" // where `e` is a type which requires a destructor. -// pretty-expanded FIXME #23616 struct Foo; struct Bar { x: isize } diff --git a/src/test/run-pass/issue-7575.rs b/src/test/run-pass/issue-7575.rs index 727ed91eadc6c..508ebf3f69d1a 100644 --- a/src/test/run-pass/issue-7575.rs +++ b/src/test/run-pass/issue-7575.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn new() -> bool { false } diff --git a/src/test/run-pass/issue-7663.rs b/src/test/run-pass/issue-7663.rs index 007127aeae186..7aac8d4456334 100644 --- a/src/test/run-pass/issue-7663.rs +++ b/src/test/run-pass/issue-7663.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unused_imports, dead_code)] diff --git a/src/test/run-pass/issue-7784.rs b/src/test/run-pass/issue-7784.rs index e2016feeb0ad7..224fe627e32d9 100644 --- a/src/test/run-pass/issue-7784.rs +++ b/src/test/run-pass/issue-7784.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] diff --git a/src/test/run-pass/issue-8351-1.rs b/src/test/run-pass/issue-8351-1.rs index a11e14fb33367..ed78b37604e86 100644 --- a/src/test/run-pass/issue-8351-1.rs +++ b/src/test/run-pass/issue-8351-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { Foo{f: isize}, diff --git a/src/test/run-pass/issue-8351-2.rs b/src/test/run-pass/issue-8351-2.rs index 7cf221926a6d3..1ed93915b8a03 100644 --- a/src/test/run-pass/issue-8351-2.rs +++ b/src/test/run-pass/issue-8351-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { Foo{f: isize, b: bool}, diff --git a/src/test/run-pass/issue-8391.rs b/src/test/run-pass/issue-8391.rs index bd2e2871bdb49..b832c410443c4 100644 --- a/src/test/run-pass/issue-8391.rs +++ b/src/test/run-pass/issue-8391.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { let x = match Some(1) { diff --git a/src/test/run-pass/issue-8460.rs b/src/test/run-pass/issue-8460.rs index 7d8c4ab210d00..2469dec994727 100644 --- a/src/test/run-pass/issue-8460.rs +++ b/src/test/run-pass/issue-8460.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/issue-8498.rs b/src/test/run-pass/issue-8498.rs index 825729b1e2a81..fae3352f9cc5f 100644 --- a/src/test/run-pass/issue-8498.rs +++ b/src/test/run-pass/issue-8498.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { match &[(Box::new(5),Box::new(7))] { diff --git a/src/test/run-pass/issue-8709.rs b/src/test/run-pass/issue-8709.rs index 6467262929810..44759cef2864f 100644 --- a/src/test/run-pass/issue-8709.rs +++ b/src/test/run-pass/issue-8709.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! sty { ($t:ty) => (stringify!($t)) diff --git a/src/test/run-pass/issue-8860.rs b/src/test/run-pass/issue-8860.rs index 8024eaeda83cb..ff562aac1614b 100644 --- a/src/test/run-pass/issue-8860.rs +++ b/src/test/run-pass/issue-8860.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 static mut DROP: isize = 0; static mut DROP_S: isize = 0; diff --git a/src/test/run-pass/issue-8898.rs b/src/test/run-pass/issue-8898.rs index a4cad1b263952..065cef2c60d7d 100644 --- a/src/test/run-pass/issue-8898.rs +++ b/src/test/run-pass/issue-8898.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn assert_repr_eq(obj : T, expected : String) { assert_eq!(expected, format!("{:?}", obj)); diff --git a/src/test/run-pass/issue-9188.rs b/src/test/run-pass/issue-9188.rs index 0bd8a8e0d9df2..e2272837efb7a 100644 --- a/src/test/run-pass/issue-9188.rs +++ b/src/test/run-pass/issue-9188.rs @@ -10,7 +10,6 @@ // aux-build:issue_9188.rs -// pretty-expanded FIXME #23616 extern crate issue_9188; diff --git a/src/test/run-pass/issue-9259.rs b/src/test/run-pass/issue-9259.rs index 209c6b139612f..996548de81738 100644 --- a/src/test/run-pass/issue-9259.rs +++ b/src/test/run-pass/issue-9259.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct A<'a> { a: &'a [String], diff --git a/src/test/run-pass/issue-9394-inherited-trait-calls.rs b/src/test/run-pass/issue-9394-inherited-trait-calls.rs index 148d0760e5c02..7d2c435b38429 100644 --- a/src/test/run-pass/issue-9394-inherited-trait-calls.rs +++ b/src/test/run-pass/issue-9394-inherited-trait-calls.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Base: Base2 + Base3{ fn foo(&self) -> String; diff --git a/src/test/run-pass/issue-979.rs b/src/test/run-pass/issue-979.rs index 3283dc44f3083..979abcef7b8d2 100644 --- a/src/test/run-pass/issue-979.rs +++ b/src/test/run-pass/issue-979.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/issue-9918.rs b/src/test/run-pass/issue-9918.rs index e81a07fa68325..a766e6b707e30 100644 --- a/src/test/run-pass/issue-9918.rs +++ b/src/test/run-pass/issue-9918.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { assert_eq!((0 + 0u8) as char, '\0'); diff --git a/src/test/run-pass/iter-cloned-type-inference.rs b/src/test/run-pass/iter-cloned-type-inference.rs index d1f63564979c8..59f7569d8c62b 100644 --- a/src/test/run-pass/iter-cloned-type-inference.rs +++ b/src/test/run-pass/iter-cloned-type-inference.rs @@ -11,7 +11,6 @@ // Test to see that the element type of .cloned() can be inferred // properly. Previously this would fail to deduce the type of `sum`. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/kindck-owned-trait-contains-1.rs b/src/test/run-pass/kindck-owned-trait-contains-1.rs index 84156385ef438..9df72f4760a1f 100644 --- a/src/test/run-pass/kindck-owned-trait-contains-1.rs +++ b/src/test/run-pass/kindck-owned-trait-contains-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/last-use-in-block.rs b/src/test/run-pass/last-use-in-block.rs index 28fe3bf0bd1fd..a2b01f29ae127 100644 --- a/src/test/run-pass/last-use-in-block.rs +++ b/src/test/run-pass/last-use-in-block.rs @@ -10,7 +10,6 @@ // Issue #1818 -// pretty-expanded FIXME #23616 fn lp(s: String, mut f: F) -> T where F: FnMut(String) -> T { while false { diff --git a/src/test/run-pass/last-use-in-cap-clause.rs b/src/test/run-pass/last-use-in-cap-clause.rs index f9c8fe0f2d2d5..f196899f69d68 100644 --- a/src/test/run-pass/last-use-in-cap-clause.rs +++ b/src/test/run-pass/last-use-in-cap-clause.rs @@ -10,7 +10,6 @@ // Make sure #1399 stays fixed -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/let-destruct-ref.rs b/src/test/run-pass/let-destruct-ref.rs index 0b38d16941bae..c9504f87c4904 100644 --- a/src/test/run-pass/let-destruct-ref.rs +++ b/src/test/run-pass/let-destruct-ref.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = 3_usize; diff --git a/src/test/run-pass/let-var-hygiene.rs b/src/test/run-pass/let-var-hygiene.rs index c1e80aaf2d7b0..d9087f58befe7 100644 --- a/src/test/run-pass/let-var-hygiene.rs +++ b/src/test/run-pass/let-var-hygiene.rs @@ -9,7 +9,6 @@ // except according to those terms. // shouldn't affect evaluation of $ex: -// pretty-expanded FIXME #23616 macro_rules! bad_macro { ($ex:expr) => ({let _x = 9; $ex}) diff --git a/src/test/run-pass/logging-enabled-debug.rs b/src/test/run-pass/logging-enabled-debug.rs index 59f5b0af35913..3ae4884ce47fc 100644 --- a/src/test/run-pass/logging-enabled-debug.rs +++ b/src/test/run-pass/logging-enabled-debug.rs @@ -11,7 +11,6 @@ // compile-flags:-C debug-assertions=no // exec-env:RUST_LOG=logging-enabled-debug=debug -// pretty-expanded FIXME #23616 #![feature(rustc_private)] diff --git a/src/test/run-pass/logging-enabled.rs b/src/test/run-pass/logging-enabled.rs index 294d4d1217952..2975835a27149 100644 --- a/src/test/run-pass/logging-enabled.rs +++ b/src/test/run-pass/logging-enabled.rs @@ -10,7 +10,6 @@ // exec-env:RUST_LOG=logging_enabled=info -// pretty-expanded FIXME #23616 #![feature(rustc_private)] diff --git a/src/test/run-pass/loop-break-cont-1.rs b/src/test/run-pass/loop-break-cont-1.rs index eaf69dbae00f9..5abac0e65a360 100644 --- a/src/test/run-pass/loop-break-cont-1.rs +++ b/src/test/run-pass/loop-break-cont-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let _i = 0_usize; diff --git a/src/test/run-pass/loop-scope.rs b/src/test/run-pass/loop-scope.rs index 70f2830555a4b..0c1e7916cdb18 100644 --- a/src/test/run-pass/loop-scope.rs +++ b/src/test/run-pass/loop-scope.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = vec!(10, 20, 30); diff --git a/src/test/run-pass/macro-block-nonterminal.rs b/src/test/run-pass/macro-block-nonterminal.rs index 496534a5362f3..21b284f420f20 100644 --- a/src/test/run-pass/macro-block-nonterminal.rs +++ b/src/test/run-pass/macro-block-nonterminal.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! do_block{ ($val:block) => {$val} diff --git a/src/test/run-pass/macro-crate-def-only.rs b/src/test/run-pass/macro-crate-def-only.rs index 58b09fa492192..28be058b9a376 100644 --- a/src/test/run-pass/macro-crate-def-only.rs +++ b/src/test/run-pass/macro-crate-def-only.rs @@ -10,7 +10,6 @@ // aux-build:macro_crate_def_only.rs -// pretty-expanded FIXME #23616 #[macro_use] #[no_link] extern crate macro_crate_def_only; diff --git a/src/test/run-pass/macro-crate-use.rs b/src/test/run-pass/macro-crate-use.rs index 557f982713a17..c7255f67fa684 100644 --- a/src/test/run-pass/macro-crate-use.rs +++ b/src/test/run-pass/macro-crate-use.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn increment(x: usize) -> usize { x + 1 diff --git a/src/test/run-pass/macro-deep_expansion.rs b/src/test/run-pass/macro-deep_expansion.rs index fd21ed0150ab0..3e8548ff49d2b 100644 --- a/src/test/run-pass/macro-deep_expansion.rs +++ b/src/test/run-pass/macro-deep_expansion.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! foo2 { () => { diff --git a/src/test/run-pass/macro-interpolation.rs b/src/test/run-pass/macro-interpolation.rs index e6b5d50b36e6d..6dcd1538ebce2 100644 --- a/src/test/run-pass/macro-interpolation.rs +++ b/src/test/run-pass/macro-interpolation.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! overly_complicated { ($fnname:ident, $arg:ident, $ty:ty, $body:block, $val:expr, $pat:pat, $res:path) => diff --git a/src/test/run-pass/macro-method-issue-4621.rs b/src/test/run-pass/macro-method-issue-4621.rs index cb1540459771b..64648cae5e6cc 100644 --- a/src/test/run-pass/macro-method-issue-4621.rs +++ b/src/test/run-pass/macro-method-issue-4621.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct A; diff --git a/src/test/run-pass/macro-of-higher-order.rs b/src/test/run-pass/macro-of-higher-order.rs index ebd58f772284a..52e19b37d7935 100644 --- a/src/test/run-pass/macro-of-higher-order.rs +++ b/src/test/run-pass/macro-of-higher-order.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! higher_order { (subst $lhs:tt => $rhs:tt) => ({ diff --git a/src/test/run-pass/macro-pat.rs b/src/test/run-pass/macro-pat.rs index 659113d4e0c95..48e521de57e90 100644 --- a/src/test/run-pass/macro-pat.rs +++ b/src/test/run-pass/macro-pat.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! mypat { () => ( diff --git a/src/test/run-pass/macro-path.rs b/src/test/run-pass/macro-path.rs index 2e8806229778e..7aecc1dc20348 100644 --- a/src/test/run-pass/macro-path.rs +++ b/src/test/run-pass/macro-path.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod m { pub type t = isize; diff --git a/src/test/run-pass/macro-with-attrs1.rs b/src/test/run-pass/macro-with-attrs1.rs index 0938c16c30492..99bf71b1f0126 100644 --- a/src/test/run-pass/macro-with-attrs1.rs +++ b/src/test/run-pass/macro-with-attrs1.rs @@ -10,7 +10,6 @@ // compile-flags: --cfg foo -// pretty-expanded FIXME #23616 #[cfg(foo)] macro_rules! foo { () => (1) } diff --git a/src/test/run-pass/macro-with-attrs2.rs b/src/test/run-pass/macro-with-attrs2.rs index cf48c325f1f24..062c8d55d5296 100644 --- a/src/test/run-pass/macro-with-attrs2.rs +++ b/src/test/run-pass/macro-with-attrs2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[cfg(foo)] macro_rules! foo { () => (1) } diff --git a/src/test/run-pass/match-arm-statics.rs b/src/test/run-pass/match-arm-statics.rs index 1b4dfb869d413..43ff69fe75e6c 100644 --- a/src/test/run-pass/match-arm-statics.rs +++ b/src/test/run-pass/match-arm-statics.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct NewBool(bool); diff --git a/src/test/run-pass/match-borrowed_str.rs b/src/test/run-pass/match-borrowed_str.rs index 574c4b9f00eab..b027e62494c23 100644 --- a/src/test/run-pass/match-borrowed_str.rs +++ b/src/test/run-pass/match-borrowed_str.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unnecessary_allocation)] diff --git a/src/test/run-pass/match-bot-2.rs b/src/test/run-pass/match-bot-2.rs index 4fa951b34794b..88c514a724f2f 100644 --- a/src/test/run-pass/match-bot-2.rs +++ b/src/test/run-pass/match-bot-2.rs @@ -9,7 +9,6 @@ // except according to those terms. // n.b. This was only ever failing with optimization disabled. -// pretty-expanded FIXME #23616 fn a() -> isize { match return 1 { 2 => 3, _ => panic!() } } pub fn main() { a(); } diff --git a/src/test/run-pass/match-enum-struct-0.rs b/src/test/run-pass/match-enum-struct-0.rs index 06d19cec185bb..1754dc0c960f8 100644 --- a/src/test/run-pass/match-enum-struct-0.rs +++ b/src/test/run-pass/match-enum-struct-0.rs @@ -10,7 +10,6 @@ // regression test for issue #5625 -// pretty-expanded FIXME #23616 enum E { Foo{f : isize}, diff --git a/src/test/run-pass/match-enum-struct-1.rs b/src/test/run-pass/match-enum-struct-1.rs index e4766f32a57f3..ebf2db36700c3 100644 --- a/src/test/run-pass/match-enum-struct-1.rs +++ b/src/test/run-pass/match-enum-struct-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { Foo{f : isize}, diff --git a/src/test/run-pass/match-implicit-copy-unique.rs b/src/test/run-pass/match-implicit-copy-unique.rs index d481c02eb410a..d75bdaf4da8ea 100644 --- a/src/test/run-pass/match-implicit-copy-unique.rs +++ b/src/test/run-pass/match-implicit-copy-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/match-in-macro.rs b/src/test/run-pass/match-in-macro.rs index 27bbbc936ae5c..e096c97e16f16 100644 --- a/src/test/run-pass/match-in-macro.rs +++ b/src/test/run-pass/match-in-macro.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum Foo { B { b1: isize, bb1: isize}, diff --git a/src/test/run-pass/match-pattern-bindings.rs b/src/test/run-pass/match-pattern-bindings.rs index d230f18f2bd84..9f687ab99e800 100644 --- a/src/test/run-pass/match-pattern-bindings.rs +++ b/src/test/run-pass/match-pattern-bindings.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { let value = Some(1); diff --git a/src/test/run-pass/match-pipe-binding.rs b/src/test/run-pass/match-pipe-binding.rs index 70d3639a785fa..bda90d3aaecb4 100644 --- a/src/test/run-pass/match-pipe-binding.rs +++ b/src/test/run-pass/match-pipe-binding.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn test1() { // from issue 6338 diff --git a/src/test/run-pass/match-ref-binding-in-guard-3256.rs b/src/test/run-pass/match-ref-binding-in-guard-3256.rs index 1e2ebf42a9911..dc3c759078f3d 100644 --- a/src/test/run-pass/match-ref-binding-in-guard-3256.rs +++ b/src/test/run-pass/match-ref-binding-in-guard-3256.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::sync::Mutex; diff --git a/src/test/run-pass/match-ref-binding-mut-option.rs b/src/test/run-pass/match-ref-binding-mut-option.rs index 41f00e58ff769..f429e7b58e382 100644 --- a/src/test/run-pass/match-ref-binding-mut-option.rs +++ b/src/test/run-pass/match-ref-binding-mut-option.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let mut v = Some(22); diff --git a/src/test/run-pass/match-ref-binding-mut.rs b/src/test/run-pass/match-ref-binding-mut.rs index 26c91e1703caf..abc418ddd5169 100644 --- a/src/test/run-pass/match-ref-binding-mut.rs +++ b/src/test/run-pass/match-ref-binding-mut.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Rec { f: isize diff --git a/src/test/run-pass/match-ref-binding.rs b/src/test/run-pass/match-ref-binding.rs index 826edb30b36f4..eab7ed529b1f6 100644 --- a/src/test/run-pass/match-ref-binding.rs +++ b/src/test/run-pass/match-ref-binding.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn destructure(x: Option) -> isize { match x { diff --git a/src/test/run-pass/match-static-const-rename.rs b/src/test/run-pass/match-static-const-rename.rs index 21b806f80dee4..08f3182900fc2 100644 --- a/src/test/run-pass/match-static-const-rename.rs +++ b/src/test/run-pass/match-static-const-rename.rs @@ -16,7 +16,6 @@ // around this problem locally by renaming the constant in the `use` // form to an uppercase identifier that placates the lint. -// pretty-expanded FIXME #23616 #![deny(non_upper_case_globals)] diff --git a/src/test/run-pass/match-str.rs b/src/test/run-pass/match-str.rs index 5d8958c6b9e87..e6def65e53a6f 100644 --- a/src/test/run-pass/match-str.rs +++ b/src/test/run-pass/match-str.rs @@ -10,7 +10,6 @@ // Issue #53 -// pretty-expanded FIXME #23616 pub fn main() { match "test" { "not-test" => panic!(), "test" => (), _ => panic!() } diff --git a/src/test/run-pass/match-struct-0.rs b/src/test/run-pass/match-struct-0.rs index 450b310b8f408..e9e45df460df1 100644 --- a/src/test/run-pass/match-struct-0.rs +++ b/src/test/run-pass/match-struct-0.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Foo{ f : isize, diff --git a/src/test/run-pass/match-tag.rs b/src/test/run-pass/match-tag.rs index 82d29f9050bfc..e4a0d4e95f3c7 100644 --- a/src/test/run-pass/match-tag.rs +++ b/src/test/run-pass/match-tag.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 enum color { rgb(isize, isize, isize), diff --git a/src/test/run-pass/match-vec-alternatives.rs b/src/test/run-pass/match-vec-alternatives.rs index f9b49281bab0c..43e0b442251bd 100644 --- a/src/test/run-pass/match-vec-alternatives.rs +++ b/src/test/run-pass/match-vec-alternatives.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] diff --git a/src/test/run-pass/match-vec-rvalue.rs b/src/test/run-pass/match-vec-rvalue.rs index e368aeb976934..a10f9b1d7d61b 100644 --- a/src/test/run-pass/match-vec-rvalue.rs +++ b/src/test/run-pass/match-vec-rvalue.rs @@ -11,7 +11,6 @@ // Tests that matching rvalues with drops does not crash. -// pretty-expanded FIXME #23616 pub fn main() { match vec!(1, 2, 3) { diff --git a/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs b/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs index 7cc762c934826..25e0b272fd2e5 100644 --- a/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs +++ b/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs @@ -12,7 +12,6 @@ // type is `&mut [u8]`, passes in a pointer to the lvalue and not a // temporary. Issue #19147. -// pretty-expanded FIXME #23616 #![feature(core, old_io)] diff --git a/src/test/run-pass/method-projection.rs b/src/test/run-pass/method-projection.rs index 3db7268207086..41d92cc75937b 100644 --- a/src/test/run-pass/method-projection.rs +++ b/src/test/run-pass/method-projection.rs @@ -13,7 +13,6 @@ /////////////////////////////////////////////////////////////////////////// -// pretty-expanded FIXME #23616 trait MakeString { fn make_string(&self) -> String; diff --git a/src/test/run-pass/method-self-arg-aux1.rs b/src/test/run-pass/method-self-arg-aux1.rs index 768e7f94862ac..acda78af5c32d 100644 --- a/src/test/run-pass/method-self-arg-aux1.rs +++ b/src/test/run-pass/method-self-arg-aux1.rs @@ -10,7 +10,6 @@ // Test method calls with self as an argument (cross-crate) -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/method-self-arg-aux2.rs b/src/test/run-pass/method-self-arg-aux2.rs index b40333c67c6ac..0aea4139b0c37 100644 --- a/src/test/run-pass/method-self-arg-aux2.rs +++ b/src/test/run-pass/method-self-arg-aux2.rs @@ -10,7 +10,6 @@ // Test method calls with self as an argument (cross-crate) -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/method-self-arg-trait.rs b/src/test/run-pass/method-self-arg-trait.rs index f0ca0a70acc96..2ba3e78ef1504 100644 --- a/src/test/run-pass/method-self-arg-trait.rs +++ b/src/test/run-pass/method-self-arg-trait.rs @@ -10,7 +10,6 @@ // Test method calls with self as an argument -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/method-self-arg.rs b/src/test/run-pass/method-self-arg.rs index dfc121192228d..543133a3268f8 100644 --- a/src/test/run-pass/method-self-arg.rs +++ b/src/test/run-pass/method-self-arg.rs @@ -10,7 +10,6 @@ // Test method calls with self as an argument -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/method-two-trait-defer-resolution-1.rs b/src/test/run-pass/method-two-trait-defer-resolution-1.rs index d0e0427f37808..ff80ee1986815 100644 --- a/src/test/run-pass/method-two-trait-defer-resolution-1.rs +++ b/src/test/run-pass/method-two-trait-defer-resolution-1.rs @@ -11,7 +11,6 @@ // Test that we pick which version of `foo` to run based on the // type that is (ultimately) inferred for `x`. -// pretty-expanded FIXME #23616 trait foo { fn foo(&self) -> i32; diff --git a/src/test/run-pass/method-two-trait-defer-resolution-2.rs b/src/test/run-pass/method-two-trait-defer-resolution-2.rs index 2ceff22adb9eb..e1b64f250d8e1 100644 --- a/src/test/run-pass/method-two-trait-defer-resolution-2.rs +++ b/src/test/run-pass/method-two-trait-defer-resolution-2.rs @@ -19,7 +19,6 @@ // translate the call as `Foo::foo(&x)` and let the specific impl get // chosen later. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/method-where-clause.rs b/src/test/run-pass/method-where-clause.rs index f2ff0abfad8b8..078dbe0e79e7f 100644 --- a/src/test/run-pass/method-where-clause.rs +++ b/src/test/run-pass/method-where-clause.rs @@ -11,7 +11,6 @@ // Test that we can use method notation to call methods based on a // where clause type, and not only type parameters. -// pretty-expanded FIXME #23616 trait Foo { fn foo(&self) -> i32; diff --git a/src/test/run-pass/mod-inside-fn.rs b/src/test/run-pass/mod-inside-fn.rs index 836f2960d7174..6b922634aade1 100644 --- a/src/test/run-pass/mod-inside-fn.rs +++ b/src/test/run-pass/mod-inside-fn.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn f() -> isize { mod m { diff --git a/src/test/run-pass/monad.rs b/src/test/run-pass/monad.rs index 9ccb8f2e6fdd9..e309fa14302ca 100644 --- a/src/test/run-pass/monad.rs +++ b/src/test/run-pass/monad.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 trait vec_monad { fn bind(&self, f: F ) -> Vec where F: FnMut(&A) -> Vec ; diff --git a/src/test/run-pass/move-1-unique.rs b/src/test/run-pass/move-1-unique.rs index ab9770b13d451..34a3bdf876538 100644 --- a/src/test/run-pass/move-1-unique.rs +++ b/src/test/run-pass/move-1-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-2-unique.rs b/src/test/run-pass/move-2-unique.rs index c65e58a7b6502..e4dc82f9801d1 100644 --- a/src/test/run-pass/move-2-unique.rs +++ b/src/test/run-pass/move-2-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-2.rs b/src/test/run-pass/move-2.rs index 054b57b2f432e..0c89c89eb8aa0 100644 --- a/src/test/run-pass/move-2.rs +++ b/src/test/run-pass/move-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-3-unique.rs b/src/test/run-pass/move-3-unique.rs index 6036fa26ccf99..360593ffe4882 100644 --- a/src/test/run-pass/move-3-unique.rs +++ b/src/test/run-pass/move-3-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-4-unique.rs b/src/test/run-pass/move-4-unique.rs index 79a1b294da9bb..9f80ecf297935 100644 --- a/src/test/run-pass/move-4-unique.rs +++ b/src/test/run-pass/move-4-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-4.rs b/src/test/run-pass/move-4.rs index 16ef95023542b..1346860d51d7b 100644 --- a/src/test/run-pass/move-4.rs +++ b/src/test/run-pass/move-4.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-arg-2-unique.rs b/src/test/run-pass/move-arg-2-unique.rs index 7aec948c8d472..fa69731963a30 100644 --- a/src/test/run-pass/move-arg-2-unique.rs +++ b/src/test/run-pass/move-arg-2-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-arg-2.rs b/src/test/run-pass/move-arg-2.rs index 69b66d81e4355..6e22deed269da 100644 --- a/src/test/run-pass/move-arg-2.rs +++ b/src/test/run-pass/move-arg-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-arg.rs b/src/test/run-pass/move-arg.rs index 3d9eba8c09f20..0ff9a35874bfc 100644 --- a/src/test/run-pass/move-arg.rs +++ b/src/test/run-pass/move-arg.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn test(foo: isize) { assert!((foo == 10)); } diff --git a/src/test/run-pass/move-out-of-field.rs b/src/test/run-pass/move-out-of-field.rs index a0eba4685b887..262add090bde7 100644 --- a/src/test/run-pass/move-out-of-field.rs +++ b/src/test/run-pass/move-out-of-field.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::string::String; diff --git a/src/test/run-pass/move-scalar.rs b/src/test/run-pass/move-scalar.rs index a5b0a8b9bf482..798424d107e27 100644 --- a/src/test/run-pass/move-scalar.rs +++ b/src/test/run-pass/move-scalar.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { diff --git a/src/test/run-pass/multi-let.rs b/src/test/run-pass/multi-let.rs index 658b34e13f99b..1079857c1b387 100644 --- a/src/test/run-pass/multi-let.rs +++ b/src/test/run-pass/multi-let.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = 10; diff --git a/src/test/run-pass/multidispatch1.rs b/src/test/run-pass/multidispatch1.rs index fdf9f95b274d4..7137a4109b151 100644 --- a/src/test/run-pass/multidispatch1.rs +++ b/src/test/run-pass/multidispatch1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::fmt::Debug; diff --git a/src/test/run-pass/multidispatch2.rs b/src/test/run-pass/multidispatch2.rs index 75c6c5ac7d165..1573c0234a6e4 100644 --- a/src/test/run-pass/multidispatch2.rs +++ b/src/test/run-pass/multidispatch2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::fmt::Debug; use std::default::Default; diff --git a/src/test/run-pass/mut-function-arguments.rs b/src/test/run-pass/mut-function-arguments.rs index 644e45575521e..f415a7f2d668c 100644 --- a/src/test/run-pass/mut-function-arguments.rs +++ b/src/test/run-pass/mut-function-arguments.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/mut-in-ident-patterns.rs b/src/test/run-pass/mut-in-ident-patterns.rs index 2a8f6f1fc31ea..32ff7efffa0dc 100644 --- a/src/test/run-pass/mut-in-ident-patterns.rs +++ b/src/test/run-pass/mut-in-ident-patterns.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn foo(&self, mut x: isize) -> isize { diff --git a/src/test/run-pass/mutability-inherits-through-fixed-length-vec.rs b/src/test/run-pass/mutability-inherits-through-fixed-length-vec.rs index bed3b87def58b..1766e65b9c734 100644 --- a/src/test/run-pass/mutability-inherits-through-fixed-length-vec.rs +++ b/src/test/run-pass/mutability-inherits-through-fixed-length-vec.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn test1() { let mut ints = [0; 32]; diff --git a/src/test/run-pass/negative.rs b/src/test/run-pass/negative.rs index c5b6a6a035bba..df074ddc06ac5 100644 --- a/src/test/run-pass/negative.rs +++ b/src/test/run-pass/negative.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { match -5 { diff --git a/src/test/run-pass/nested-class.rs b/src/test/run-pass/nested-class.rs index 86197d44a689d..1ad68cb9de052 100644 --- a/src/test/run-pass/nested-class.rs +++ b/src/test/run-pass/nested-class.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { struct b { diff --git a/src/test/run-pass/nested-function-names-issue-8587.rs b/src/test/run-pass/nested-function-names-issue-8587.rs index 28f3438f9862b..24b1f5ac75eae 100644 --- a/src/test/run-pass/nested-function-names-issue-8587.rs +++ b/src/test/run-pass/nested-function-names-issue-8587.rs @@ -13,7 +13,6 @@ // // Issue #8587 -// pretty-expanded FIXME #23616 pub struct X; diff --git a/src/test/run-pass/nested_item_main.rs b/src/test/run-pass/nested_item_main.rs index f7adfe36695d2..b24d517f7375c 100644 --- a/src/test/run-pass/nested_item_main.rs +++ b/src/test/run-pass/nested_item_main.rs @@ -10,7 +10,6 @@ // aux-build:nested_item.rs -// pretty-expanded FIXME #23616 extern crate nested_item; diff --git a/src/test/run-pass/new-unicode-escapes.rs b/src/test/run-pass/new-unicode-escapes.rs index 8c2d5e09adb47..bfad79e92d2c2 100644 --- a/src/test/run-pass/new-unicode-escapes.rs +++ b/src/test/run-pass/new-unicode-escapes.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections)] diff --git a/src/test/run-pass/newlambdas.rs b/src/test/run-pass/newlambdas.rs index c6fa7cc35fd9a..a6f39958632c2 100644 --- a/src/test/run-pass/newlambdas.rs +++ b/src/test/run-pass/newlambdas.rs @@ -10,7 +10,6 @@ // Tests for the new |args| expr lambda syntax -// pretty-expanded FIXME #23616 fn f(i: isize, f: F) -> isize where F: FnOnce(isize) -> isize { f(i) } diff --git a/src/test/run-pass/newtype-polymorphic.rs b/src/test/run-pass/newtype-polymorphic.rs index 424d518895cfb..91599608ceed6 100644 --- a/src/test/run-pass/newtype-polymorphic.rs +++ b/src/test/run-pass/newtype-polymorphic.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Clone)] struct myvec(Vec ); diff --git a/src/test/run-pass/newtype-struct-drop-run.rs b/src/test/run-pass/newtype-struct-drop-run.rs index 2d162ba7e336b..4407002aca8d6 100644 --- a/src/test/run-pass/newtype-struct-drop-run.rs +++ b/src/test/run-pass/newtype-struct-drop-run.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/no-landing-pads.rs b/src/test/run-pass/no-landing-pads.rs index da57c81a66978..d90e7ef5e473d 100644 --- a/src/test/run-pass/no-landing-pads.rs +++ b/src/test/run-pass/no-landing-pads.rs @@ -10,7 +10,6 @@ // compile-flags: -Z no-landing-pads -// pretty-expanded FIXME #23616 use std::thread; diff --git a/src/test/run-pass/non-legacy-modes.rs b/src/test/run-pass/non-legacy-modes.rs index 5f1c69bb4b654..58534ed96da83 100644 --- a/src/test/run-pass/non-legacy-modes.rs +++ b/src/test/run-pass/non-legacy-modes.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct X { repr: isize diff --git a/src/test/run-pass/nul-characters.rs b/src/test/run-pass/nul-characters.rs index 25c111daad597..cbea5e71f255f 100644 --- a/src/test/run-pass/nul-characters.rs +++ b/src/test/run-pass/nul-characters.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { diff --git a/src/test/run-pass/nullable-pointer-ffi-compat.rs b/src/test/run-pass/nullable-pointer-ffi-compat.rs index 22aa09c718a74..224111900d60c 100644 --- a/src/test/run-pass/nullable-pointer-ffi-compat.rs +++ b/src/test/run-pass/nullable-pointer-ffi-compat.rs @@ -20,7 +20,6 @@ // then we simply express the enum as just a pointer and not wrap it // in a struct. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/nullable-pointer-iotareduction.rs b/src/test/run-pass/nullable-pointer-iotareduction.rs index ad2716e00de56..ced2b24f36cfe 100644 --- a/src/test/run-pass/nullable-pointer-iotareduction.rs +++ b/src/test/run-pass/nullable-pointer-iotareduction.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/nullable-pointer-size.rs b/src/test/run-pass/nullable-pointer-size.rs index 6e3f438575e2a..b097d350c8d5e 100644 --- a/src/test/run-pass/nullable-pointer-size.rs +++ b/src/test/run-pass/nullable-pointer-size.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/nullary-or-pattern.rs b/src/test/run-pass/nullary-or-pattern.rs index f4cfc80827498..feb8726c0e4a8 100644 --- a/src/test/run-pass/nullary-or-pattern.rs +++ b/src/test/run-pass/nullary-or-pattern.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum blah { a, b, } diff --git a/src/test/run-pass/numeric-method-autoexport.rs b/src/test/run-pass/numeric-method-autoexport.rs index cb41949a722c2..d5f64c1c7b1aa 100644 --- a/src/test/run-pass/numeric-method-autoexport.rs +++ b/src/test/run-pass/numeric-method-autoexport.rs @@ -15,7 +15,6 @@ // necessary. Testing the methods of the impls is done within the source // file for each numeric type. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/object-method-numbering.rs b/src/test/run-pass/object-method-numbering.rs index 8b8c56aee8391..82d34fa9ae48b 100644 --- a/src/test/run-pass/object-method-numbering.rs +++ b/src/test/run-pass/object-method-numbering.rs @@ -11,7 +11,6 @@ // Test for using an object with an associated type binding as the // instantiation for a generic type with a bound. -// pretty-expanded FIXME #23616 trait SomeTrait { type SomeType; diff --git a/src/test/run-pass/object-safety-sized-self-by-value-self.rs b/src/test/run-pass/object-safety-sized-self-by-value-self.rs index b735743927c89..81acd94ebe516 100644 --- a/src/test/run-pass/object-safety-sized-self-by-value-self.rs +++ b/src/test/run-pass/object-safety-sized-self-by-value-self.rs @@ -11,7 +11,6 @@ // Check that a trait is still object-safe (and usable) if it has // methods with by-value self so long as they require `Self : Sized`. -// pretty-expanded FIXME #23616 trait Counter { fn tick(&mut self) -> u32; diff --git a/src/test/run-pass/object-safety-sized-self-generic-method.rs b/src/test/run-pass/object-safety-sized-self-generic-method.rs index 696c5a0970914..2e84117566e47 100644 --- a/src/test/run-pass/object-safety-sized-self-generic-method.rs +++ b/src/test/run-pass/object-safety-sized-self-generic-method.rs @@ -11,7 +11,6 @@ // Check that a trait is still object-safe (and usable) if it has // generic methods so long as they require `Self : Sized`. -// pretty-expanded FIXME #23616 trait Counter { fn tick(&mut self) -> u32; diff --git a/src/test/run-pass/object-safety-sized-self-return-Self.rs b/src/test/run-pass/object-safety-sized-self-return-Self.rs index 17c41f2194b69..eda541262bd94 100644 --- a/src/test/run-pass/object-safety-sized-self-return-Self.rs +++ b/src/test/run-pass/object-safety-sized-self-return-Self.rs @@ -11,7 +11,6 @@ // Check that a trait is still object-safe (and usable) if it has // methods that return `Self` so long as they require `Self : Sized`. -// pretty-expanded FIXME #23616 trait Counter { fn new() -> Self where Self : Sized; diff --git a/src/test/run-pass/objects-coerce-freeze-borrored.rs b/src/test/run-pass/objects-coerce-freeze-borrored.rs index 686924a31400a..f907b5723f41b 100644 --- a/src/test/run-pass/objects-coerce-freeze-borrored.rs +++ b/src/test/run-pass/objects-coerce-freeze-borrored.rs @@ -10,7 +10,6 @@ // Test that we can coerce an `@Object` to an `&Object` -// pretty-expanded FIXME #23616 trait Foo { fn foo(&self) -> usize; diff --git a/src/test/run-pass/objects-owned-object-borrowed-method-headerless.rs b/src/test/run-pass/objects-owned-object-borrowed-method-headerless.rs index 9a1cdd2922f7a..176f67fd3a18a 100644 --- a/src/test/run-pass/objects-owned-object-borrowed-method-headerless.rs +++ b/src/test/run-pass/objects-owned-object-borrowed-method-headerless.rs @@ -12,7 +12,6 @@ // closed over do not contain managed values, and thus the boxes do // not have headers. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/objects-owned-object-owned-method.rs b/src/test/run-pass/objects-owned-object-owned-method.rs index 4357adbf65bfd..71ed995e76c82 100644 --- a/src/test/run-pass/objects-owned-object-owned-method.rs +++ b/src/test/run-pass/objects-owned-object-owned-method.rs @@ -12,7 +12,6 @@ // closed over contain managed values. This implies that the boxes // will have headers that must be skipped over. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/once-move-out-on-heap.rs b/src/test/run-pass/once-move-out-on-heap.rs index 7bf8b693d9bbf..6dd4c0ddce3c5 100644 --- a/src/test/run-pass/once-move-out-on-heap.rs +++ b/src/test/run-pass/once-move-out-on-heap.rs @@ -11,7 +11,6 @@ // Testing guarantees provided by once functions. -// pretty-expanded FIXME #23616 use std::sync::Arc; diff --git a/src/test/run-pass/one-tuple.rs b/src/test/run-pass/one-tuple.rs index 6520e42dbe3f8..68974b47d06a9 100644 --- a/src/test/run-pass/one-tuple.rs +++ b/src/test/run-pass/one-tuple.rs @@ -10,7 +10,6 @@ // Why one-tuples? Because macros. -// pretty-expanded FIXME #23616 pub fn main() { match ('c',) { diff --git a/src/test/run-pass/operator-associativity.rs b/src/test/run-pass/operator-associativity.rs index ccfdb83ab8aa1..78834ef914d59 100644 --- a/src/test/run-pass/operator-associativity.rs +++ b/src/test/run-pass/operator-associativity.rs @@ -12,6 +12,5 @@ // Testcase for issue #130, operator associativity. -// pretty-expanded FIXME #23616 pub fn main() { assert!((3 * 5 / 2 == 7)); } diff --git a/src/test/run-pass/option-unwrap.rs b/src/test/run-pass/option-unwrap.rs index 4902038667cd8..44f13a3eb1a52 100644 --- a/src/test/run-pass/option-unwrap.rs +++ b/src/test/run-pass/option-unwrap.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/or-pattern.rs b/src/test/run-pass/or-pattern.rs index 3ab78e8d05344..3bb0c71c58115 100644 --- a/src/test/run-pass/or-pattern.rs +++ b/src/test/run-pass/or-pattern.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum blah { a(isize, isize, usize), b(isize, isize), c, } diff --git a/src/test/run-pass/order-drop-with-match.rs b/src/test/run-pass/order-drop-with-match.rs index c8a2ba0af47cb..8f82e3aaba155 100644 --- a/src/test/run-pass/order-drop-with-match.rs +++ b/src/test/run-pass/order-drop-with-match.rs @@ -14,7 +14,6 @@ // in ORDER matching up to when it ran. // Correct order is: matched, inner, outer -// pretty-expanded FIXME #23616 static mut ORDER: [usize; 3] = [0, 0, 0]; static mut INDEX: usize = 0; diff --git a/src/test/run-pass/out-pointer-aliasing.rs b/src/test/run-pass/out-pointer-aliasing.rs index 0a58411041e64..790affd939f24 100644 --- a/src/test/run-pass/out-pointer-aliasing.rs +++ b/src/test/run-pass/out-pointer-aliasing.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] pub struct Foo { diff --git a/src/test/run-pass/overloaded-autoderef-indexing.rs b/src/test/run-pass/overloaded-autoderef-indexing.rs index fdf42423b662b..67b8bc1d157ca 100644 --- a/src/test/run-pass/overloaded-autoderef-indexing.rs +++ b/src/test/run-pass/overloaded-autoderef-indexing.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::ops::Deref; diff --git a/src/test/run-pass/overloaded-autoderef-order.rs b/src/test/run-pass/overloaded-autoderef-order.rs index 6880032e69f66..7433494dec677 100644 --- a/src/test/run-pass/overloaded-autoderef-order.rs +++ b/src/test/run-pass/overloaded-autoderef-order.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::rc::Rc; use std::ops::Deref; diff --git a/src/test/run-pass/overloaded-autoderef-vtable.rs b/src/test/run-pass/overloaded-autoderef-vtable.rs index 38bf68b746946..ed11c8c0baecc 100644 --- a/src/test/run-pass/overloaded-autoderef-vtable.rs +++ b/src/test/run-pass/overloaded-autoderef-vtable.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::ops::Deref; diff --git a/src/test/run-pass/overloaded-autoderef-xcrate.rs b/src/test/run-pass/overloaded-autoderef-xcrate.rs index b97fb49112484..174e09cb14c7a 100644 --- a/src/test/run-pass/overloaded-autoderef-xcrate.rs +++ b/src/test/run-pass/overloaded-autoderef-xcrate.rs @@ -10,7 +10,6 @@ // aux-build:overloaded_autoderef_xc.rs -// pretty-expanded FIXME #23616 extern crate overloaded_autoderef_xc; diff --git a/src/test/run-pass/overloaded-calls-object-one-arg.rs b/src/test/run-pass/overloaded-calls-object-one-arg.rs index 291d2c6498f99..ec64f627c9462 100644 --- a/src/test/run-pass/overloaded-calls-object-one-arg.rs +++ b/src/test/run-pass/overloaded-calls-object-one-arg.rs @@ -11,7 +11,6 @@ // Tests calls to closure arguments where the closure takes 1 argument. // This is a bit tricky due to rust-call ABI. -// pretty-expanded FIXME #23616 fn foo(f: &mut FnMut(isize) -> isize) -> isize { f(22) diff --git a/src/test/run-pass/overloaded-calls-object-two-args.rs b/src/test/run-pass/overloaded-calls-object-two-args.rs index 42c71572a3a94..c38a62147a011 100644 --- a/src/test/run-pass/overloaded-calls-object-two-args.rs +++ b/src/test/run-pass/overloaded-calls-object-two-args.rs @@ -11,7 +11,6 @@ // Tests calls to closure arguments where the closure takes 2 arguments. // This is a bit tricky due to rust-call ABI. -// pretty-expanded FIXME #23616 fn foo(f: &mut FnMut(isize, isize) -> isize) -> isize { f(1, 2) diff --git a/src/test/run-pass/overloaded-calls-object-zero-args.rs b/src/test/run-pass/overloaded-calls-object-zero-args.rs index 9bc6c9f042835..08ab465ebb04c 100644 --- a/src/test/run-pass/overloaded-calls-object-zero-args.rs +++ b/src/test/run-pass/overloaded-calls-object-zero-args.rs @@ -11,7 +11,6 @@ // Tests calls to closure arguments where the closure takes 0 arguments. // This is a bit tricky due to rust-call ABI. -// pretty-expanded FIXME #23616 fn foo(f: &mut FnMut() -> isize) -> isize { f() diff --git a/src/test/run-pass/overloaded-calls-simple.rs b/src/test/run-pass/overloaded-calls-simple.rs index eeb705a2e3c99..6566f6c1260cd 100644 --- a/src/test/run-pass/overloaded-calls-simple.rs +++ b/src/test/run-pass/overloaded-calls-simple.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(lang_items, unboxed_closures, core)] diff --git a/src/test/run-pass/overloaded-calls-zero-args.rs b/src/test/run-pass/overloaded-calls-zero-args.rs index 8df4adf6713c4..621b2f9420938 100644 --- a/src/test/run-pass/overloaded-calls-zero-args.rs +++ b/src/test/run-pass/overloaded-calls-zero-args.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures, core)] diff --git a/src/test/run-pass/overloaded-deref-count.rs b/src/test/run-pass/overloaded-deref-count.rs index 5f6eb87ae1be4..a8a3b3014e099 100644 --- a/src/test/run-pass/overloaded-deref-count.rs +++ b/src/test/run-pass/overloaded-deref-count.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::cell::Cell; use std::ops::{Deref, DerefMut}; diff --git a/src/test/run-pass/overloaded-index-assoc-list.rs b/src/test/run-pass/overloaded-index-assoc-list.rs index d98b1d9deae62..455099f1eba8f 100644 --- a/src/test/run-pass/overloaded-index-assoc-list.rs +++ b/src/test/run-pass/overloaded-index-assoc-list.rs @@ -11,7 +11,6 @@ // Test overloading of the `[]` operator. In particular test that it // takes its argument *by reference*. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/overloaded-index-autoderef.rs b/src/test/run-pass/overloaded-index-autoderef.rs index 56d71edd56cd0..efa0051493414 100644 --- a/src/test/run-pass/overloaded-index-autoderef.rs +++ b/src/test/run-pass/overloaded-index-autoderef.rs @@ -10,7 +10,6 @@ // Test overloaded indexing combined with autoderef. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, core)] diff --git a/src/test/run-pass/overloaded-index-in-field.rs b/src/test/run-pass/overloaded-index-in-field.rs index bc53836aca3ef..ff867e76810a6 100644 --- a/src/test/run-pass/overloaded-index-in-field.rs +++ b/src/test/run-pass/overloaded-index-in-field.rs @@ -11,7 +11,6 @@ // Test using overloaded indexing when the "map" is stored in a // field. This caused problems at some point. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/overloaded-index.rs b/src/test/run-pass/overloaded-index.rs index 4f8cf0e9e38ef..fa3c107697e67 100644 --- a/src/test/run-pass/overloaded-index.rs +++ b/src/test/run-pass/overloaded-index.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/packed-struct-borrow-element.rs b/src/test/run-pass/packed-struct-borrow-element.rs index 8819b20136105..4886874062178 100644 --- a/src/test/run-pass/packed-struct-borrow-element.rs +++ b/src/test/run-pass/packed-struct-borrow-element.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[repr(packed)] struct Foo { diff --git a/src/test/run-pass/packed-struct-generic-layout.rs b/src/test/run-pass/packed-struct-generic-layout.rs index 5d518749d9aef..e03772ddf9ff7 100644 --- a/src/test/run-pass/packed-struct-generic-layout.rs +++ b/src/test/run-pass/packed-struct-generic-layout.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/packed-struct-generic-size.rs b/src/test/run-pass/packed-struct-generic-size.rs index 6c24b71971e38..4e1f62b28ab91 100644 --- a/src/test/run-pass/packed-struct-generic-size.rs +++ b/src/test/run-pass/packed-struct-generic-size.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/packed-struct-layout.rs b/src/test/run-pass/packed-struct-layout.rs index 5d2454be2fbd5..2ac07a5d7eafc 100644 --- a/src/test/run-pass/packed-struct-layout.rs +++ b/src/test/run-pass/packed-struct-layout.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/packed-struct-match.rs b/src/test/run-pass/packed-struct-match.rs index 3c3d632222e19..3cd254014c181 100644 --- a/src/test/run-pass/packed-struct-match.rs +++ b/src/test/run-pass/packed-struct-match.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[repr(packed)] struct Foo { diff --git a/src/test/run-pass/packed-struct-size-xc.rs b/src/test/run-pass/packed-struct-size-xc.rs index b7ea720caf76d..372693433db6f 100644 --- a/src/test/run-pass/packed-struct-size-xc.rs +++ b/src/test/run-pass/packed-struct-size-xc.rs @@ -10,7 +10,6 @@ // aux-build:packed.rs -// pretty-expanded FIXME #23616 extern crate packed; diff --git a/src/test/run-pass/packed-struct-size.rs b/src/test/run-pass/packed-struct-size.rs index 3d748c404228b..754a357333979 100644 --- a/src/test/run-pass/packed-struct-size.rs +++ b/src/test/run-pass/packed-struct-size.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/packed-tuple-struct-layout.rs b/src/test/run-pass/packed-tuple-struct-layout.rs index 9d96adc29dd36..376aadc735b60 100644 --- a/src/test/run-pass/packed-tuple-struct-layout.rs +++ b/src/test/run-pass/packed-tuple-struct-layout.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/packed-tuple-struct-size.rs b/src/test/run-pass/packed-tuple-struct-size.rs index 7b7cd5929883d..b0c8684cfe3e5 100644 --- a/src/test/run-pass/packed-tuple-struct-size.rs +++ b/src/test/run-pass/packed-tuple-struct-size.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/panic-in-dtor-drops-fields.rs b/src/test/run-pass/panic-in-dtor-drops-fields.rs index 4226fba9d3e37..f84a823d3db22 100644 --- a/src/test/run-pass/panic-in-dtor-drops-fields.rs +++ b/src/test/run-pass/panic-in-dtor-drops-fields.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::thread; diff --git a/src/test/run-pass/pattern-bound-var-in-for-each.rs b/src/test/run-pass/pattern-bound-var-in-for-each.rs index 1ab578b933257..59ead3e3e989b 100644 --- a/src/test/run-pass/pattern-bound-var-in-for-each.rs +++ b/src/test/run-pass/pattern-bound-var-in-for-each.rs @@ -12,7 +12,6 @@ // pattern-bound var is an upvar (when translating // the for-each body) -// pretty-expanded FIXME #23616 fn foo(src: usize) { diff --git a/src/test/run-pass/private-class-field.rs b/src/test/run-pass/private-class-field.rs index d32ac4b90821f..8c92a05ba2a67 100644 --- a/src/test/run-pass/private-class-field.rs +++ b/src/test/run-pass/private-class-field.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct cat { meows : usize, diff --git a/src/test/run-pass/process-remove-from-env.rs b/src/test/run-pass/process-remove-from-env.rs index 6429352f44918..c6adda6067936 100644 --- a/src/test/run-pass/process-remove-from-env.rs +++ b/src/test/run-pass/process-remove-from-env.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(old_io)] diff --git a/src/test/run-pass/range-type-infer.rs b/src/test/run-pass/range-type-infer.rs index 2d664c00ed527..b6d4d09d69727 100644 --- a/src/test/run-pass/range-type-infer.rs +++ b/src/test/run-pass/range-type-infer.rs @@ -12,7 +12,6 @@ // good as the old one. Check out issue #21672, #21595 and #21649 for // more details. -// pretty-expanded FIXME #23616 fn main() { let xs = (0..8).map(|i| i == 1u64).collect::>(); diff --git a/src/test/run-pass/range.rs b/src/test/run-pass/range.rs index 4633f73b9a007..03a8af319e819 100644 --- a/src/test/run-pass/range.rs +++ b/src/test/run-pass/range.rs @@ -10,7 +10,6 @@ // Test range syntax. -// pretty-expanded FIXME #23616 fn foo() -> isize { 42 } diff --git a/src/test/run-pass/ranges-precedence.rs b/src/test/run-pass/ranges-precedence.rs index 870d7a0bc0873..807e23c81cf4f 100644 --- a/src/test/run-pass/ranges-precedence.rs +++ b/src/test/run-pass/ranges-precedence.rs @@ -11,7 +11,6 @@ // Test that the precedence of ranges is correct -// pretty-expanded FIXME #23616 struct Foo { foo: usize, diff --git a/src/test/run-pass/readalias.rs b/src/test/run-pass/readalias.rs index d3b9e56f7d079..29e45ce8a9ad5 100644 --- a/src/test/run-pass/readalias.rs +++ b/src/test/run-pass/readalias.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 struct Point {x: isize, y: isize, z: isize} diff --git a/src/test/run-pass/rec-extend.rs b/src/test/run-pass/rec-extend.rs index 1071df84cd2bb..ffef77a4b8de4 100644 --- a/src/test/run-pass/rec-extend.rs +++ b/src/test/run-pass/rec-extend.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 struct Point {x: isize, y: isize} diff --git a/src/test/run-pass/rec-tup.rs b/src/test/run-pass/rec-tup.rs index 1644a1694269a..810888b0d8e78 100644 --- a/src/test/run-pass/rec-tup.rs +++ b/src/test/run-pass/rec-tup.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] struct Point {x: isize, y: isize} diff --git a/src/test/run-pass/rec.rs b/src/test/run-pass/rec.rs index a422aaba84b30..b47bda0931fed 100644 --- a/src/test/run-pass/rec.rs +++ b/src/test/run-pass/rec.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] struct Rect {x: isize, y: isize, w: isize, h: isize} diff --git a/src/test/run-pass/record-pat.rs b/src/test/run-pass/record-pat.rs index 6b39cc196f1e6..99bec7ab7d1fb 100644 --- a/src/test/run-pass/record-pat.rs +++ b/src/test/run-pass/record-pat.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum t1 { a(isize), b(usize), } struct T2 {x: t1, y: isize} diff --git a/src/test/run-pass/reexported-static-methods-cross-crate.rs b/src/test/run-pass/reexported-static-methods-cross-crate.rs index 3efd913cf543c..4d10503838446 100644 --- a/src/test/run-pass/reexported-static-methods-cross-crate.rs +++ b/src/test/run-pass/reexported-static-methods-cross-crate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:reexported_static_methods.rs -// pretty-expanded FIXME #23616 extern crate reexported_static_methods; diff --git a/src/test/run-pass/regions-borrow-evec-fixed.rs b/src/test/run-pass/regions-borrow-evec-fixed.rs index 7f3db86783060..6d1f2930abf32 100644 --- a/src/test/run-pass/regions-borrow-evec-fixed.rs +++ b/src/test/run-pass/regions-borrow-evec-fixed.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn foo(x: &[isize]) -> isize { x[0] diff --git a/src/test/run-pass/regions-borrow-evec-uniq.rs b/src/test/run-pass/regions-borrow-evec-uniq.rs index adf88037d2841..ec1f4eda28cc5 100644 --- a/src/test/run-pass/regions-borrow-evec-uniq.rs +++ b/src/test/run-pass/regions-borrow-evec-uniq.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn foo(x: &[isize]) -> isize { x[0] diff --git a/src/test/run-pass/regions-borrow-uniq.rs b/src/test/run-pass/regions-borrow-uniq.rs index 01a4e9c20ca5b..2a08940dab6ed 100644 --- a/src/test/run-pass/regions-borrow-uniq.rs +++ b/src/test/run-pass/regions-borrow-uniq.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/regions-bot.rs b/src/test/run-pass/regions-bot.rs index 269e30741f47a..4347cbe2dc9c2 100644 --- a/src/test/run-pass/regions-bot.rs +++ b/src/test/run-pass/regions-bot.rs @@ -10,7 +10,6 @@ // A very limited test of the "bottom" region -// pretty-expanded FIXME #23616 fn produce_static() -> &'static T { panic!(); } diff --git a/src/test/run-pass/regions-close-over-type-parameter-successfully.rs b/src/test/run-pass/regions-close-over-type-parameter-successfully.rs index cc417219ee3df..d048633519ae1 100644 --- a/src/test/run-pass/regions-close-over-type-parameter-successfully.rs +++ b/src/test/run-pass/regions-close-over-type-parameter-successfully.rs @@ -11,7 +11,6 @@ // A test where we (successfully) close over a reference into // an object. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/regions-copy-closure.rs b/src/test/run-pass/regions-copy-closure.rs index 9e3fe79197d5d..3c01a7f8923e8 100644 --- a/src/test/run-pass/regions-copy-closure.rs +++ b/src/test/run-pass/regions-copy-closure.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(unboxed_closures, core)] diff --git a/src/test/run-pass/regions-dependent-addr-of.rs b/src/test/run-pass/regions-dependent-addr-of.rs index 123806a4d9d17..a6a179c432c3c 100644 --- a/src/test/run-pass/regions-dependent-addr-of.rs +++ b/src/test/run-pass/regions-dependent-addr-of.rs @@ -11,7 +11,6 @@ // Test lifetimes are linked properly when we create dependent region pointers. // Issue #3148. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_patterns)] diff --git a/src/test/run-pass/regions-early-bound-trait-param.rs b/src/test/run-pass/regions-early-bound-trait-param.rs index 738f5dbb7b9ad..33889b27a872b 100644 --- a/src/test/run-pass/regions-early-bound-trait-param.rs +++ b/src/test/run-pass/regions-early-bound-trait-param.rs @@ -11,7 +11,6 @@ // Tests that you can use an early-bound lifetime parameter as // on of the generic parameters in a trait. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/regions-early-bound-used-in-bound-method.rs b/src/test/run-pass/regions-early-bound-used-in-bound-method.rs index 6ad8995123889..c7bc8dc0a515b 100644 --- a/src/test/run-pass/regions-early-bound-used-in-bound-method.rs +++ b/src/test/run-pass/regions-early-bound-used-in-bound-method.rs @@ -11,7 +11,6 @@ // Tests that you can use a fn lifetime parameter as part of // the value for a type parameter in a bound. -// pretty-expanded FIXME #23616 trait GetRef<'a> { fn get(&self) -> &'a isize; diff --git a/src/test/run-pass/regions-early-bound-used-in-bound.rs b/src/test/run-pass/regions-early-bound-used-in-bound.rs index 6ab95d6e497bc..3c8c78aa1169a 100644 --- a/src/test/run-pass/regions-early-bound-used-in-bound.rs +++ b/src/test/run-pass/regions-early-bound-used-in-bound.rs @@ -11,7 +11,6 @@ // Tests that you can use a fn lifetime parameter as part of // the value for a type parameter in a bound. -// pretty-expanded FIXME #23616 trait GetRef<'a, T> { fn get(&self) -> &'a T; diff --git a/src/test/run-pass/regions-early-bound-used-in-type-param.rs b/src/test/run-pass/regions-early-bound-used-in-type-param.rs index dc991e9493fe4..8d145fad004a6 100644 --- a/src/test/run-pass/regions-early-bound-used-in-type-param.rs +++ b/src/test/run-pass/regions-early-bound-used-in-type-param.rs @@ -11,7 +11,6 @@ // Tests that you can use a fn lifetime parameter as part of // the value for a type parameter in a bound. -// pretty-expanded FIXME #23616 trait Get { fn get(&self) -> T; diff --git a/src/test/run-pass/regions-escape-into-other-fn.rs b/src/test/run-pass/regions-escape-into-other-fn.rs index 3e2fec717f997..597333482fde3 100644 --- a/src/test/run-pass/regions-escape-into-other-fn.rs +++ b/src/test/run-pass/regions-escape-into-other-fn.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs b/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs index 5d171811732a1..5c80863ce859d 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::swap; diff --git a/src/test/run-pass/regions-infer-borrow-scope-view.rs b/src/test/run-pass/regions-infer-borrow-scope-view.rs index 9c200a370ad85..f9ba8e82ef715 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-view.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-view.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn view(x: &[T]) -> &[T] {x} diff --git a/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs b/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs index 59221afcefffe..a89f6f4a7b56b 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/regions-infer-borrow-scope.rs b/src/test/run-pass/regions-infer-borrow-scope.rs index 3289da3cfd87e..01f4163731145 100644 --- a/src/test/run-pass/regions-infer-borrow-scope.rs +++ b/src/test/run-pass/regions-infer-borrow-scope.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/regions-infer-call-2.rs b/src/test/run-pass/regions-infer-call-2.rs index 7e6767b0de422..b994bc7b85553 100644 --- a/src/test/run-pass/regions-infer-call-2.rs +++ b/src/test/run-pass/regions-infer-call-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn takes_two(x: &isize, y: &isize) -> isize { *x + *y } diff --git a/src/test/run-pass/regions-infer-call.rs b/src/test/run-pass/regions-infer-call.rs index bc752a1d504e3..76b93f2356b06 100644 --- a/src/test/run-pass/regions-infer-call.rs +++ b/src/test/run-pass/regions-infer-call.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn takes_two(x: &isize, y: &isize) -> isize { *x + *y } diff --git a/src/test/run-pass/regions-infer-contravariance-due-to-ret.rs b/src/test/run-pass/regions-infer-contravariance-due-to-ret.rs index 73cfbcddd9aa7..3c6bc13399960 100644 --- a/src/test/run-pass/regions-infer-contravariance-due-to-ret.rs +++ b/src/test/run-pass/regions-infer-contravariance-due-to-ret.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct boxed_int<'a> { f: &'a isize, diff --git a/src/test/run-pass/regions-lifetime-static-items-enclosing-scopes.rs b/src/test/run-pass/regions-lifetime-static-items-enclosing-scopes.rs index 451c745358ae6..d1c1ec43b40f0 100644 --- a/src/test/run-pass/regions-lifetime-static-items-enclosing-scopes.rs +++ b/src/test/run-pass/regions-lifetime-static-items-enclosing-scopes.rs @@ -11,7 +11,6 @@ // This test verifies that temporary lifetime is correctly computed // for static objects in enclosing scopes. -// pretty-expanded FIXME #23616 use std::cmp::PartialEq; diff --git a/src/test/run-pass/regions-no-variance-from-fn-generics.rs b/src/test/run-pass/regions-no-variance-from-fn-generics.rs index 89bdbfaed9e0a..d385804da5790 100644 --- a/src/test/run-pass/regions-no-variance-from-fn-generics.rs +++ b/src/test/run-pass/regions-no-variance-from-fn-generics.rs @@ -12,7 +12,6 @@ // should not upset the variance inference for actual occurrences of // that lifetime in type expressions. -// pretty-expanded FIXME #23616 pub trait HasLife<'a> { fn dummy(&'a self) { } // just to induce a variance on 'a diff --git a/src/test/run-pass/regions-params.rs b/src/test/run-pass/regions-params.rs index 5002fcce96b96..dbd52bd6b60ed 100644 --- a/src/test/run-pass/regions-params.rs +++ b/src/test/run-pass/regions-params.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn region_identity(x: &usize) -> &usize { x } diff --git a/src/test/run-pass/regions-refcell.rs b/src/test/run-pass/regions-refcell.rs index 63525b36206a4..ca6a62c10c26b 100644 --- a/src/test/run-pass/regions-refcell.rs +++ b/src/test/run-pass/regions-refcell.rs @@ -12,7 +12,6 @@ // attempting to bootstrap librustc with new destructor lifetime // semantics. -// pretty-expanded FIXME #23616 use std::collections::HashMap; use std::cell::RefCell; diff --git a/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs b/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs index a36c1b30ead0b..465f43e36b94f 100644 --- a/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs +++ b/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs @@ -17,7 +17,6 @@ // changes were caught. However, those uses in the compiler could // easily get changed or refactored away in the future. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/regions-return-interior-of-option.rs b/src/test/run-pass/regions-return-interior-of-option.rs index e6ab4a81426c2..fe1c68ff4281a 100644 --- a/src/test/run-pass/regions-return-interior-of-option.rs +++ b/src/test/run-pass/regions-return-interior-of-option.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn get(opt: &Option) -> &T { match *opt { diff --git a/src/test/run-pass/regions-trait-object-1.rs b/src/test/run-pass/regions-trait-object-1.rs index d235298857939..542dc76061fef 100644 --- a/src/test/run-pass/regions-trait-object-1.rs +++ b/src/test/run-pass/regions-trait-object-1.rs @@ -12,7 +12,6 @@ // attempting to bootstrap libsyntax; it is adapted from // `syntax::ext::tt::generic_extension`. -// pretty-expanded FIXME #23616 pub struct E<'a> { pub f: &'a u8, diff --git a/src/test/run-pass/repeat-expr-in-static.rs b/src/test/run-pass/repeat-expr-in-static.rs index 5a4475ae947b6..a040d680f9da8 100644 --- a/src/test/run-pass/repeat-expr-in-static.rs +++ b/src/test/run-pass/repeat-expr-in-static.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 static FOO: [isize; 4] = [32; 4]; static BAR: [isize; 4] = [32, 32, 32, 32]; diff --git a/src/test/run-pass/resolve-issue-2428.rs b/src/test/run-pass/resolve-issue-2428.rs index bad5b83b5484c..d3bdd54624239 100644 --- a/src/test/run-pass/resolve-issue-2428.rs +++ b/src/test/run-pass/resolve-issue-2428.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const foo: isize = 4 >> 1; enum bs { thing = foo } diff --git a/src/test/run-pass/resource-in-struct.rs b/src/test/run-pass/resource-in-struct.rs index a8426f90cc489..c1e1ff0658b6e 100644 --- a/src/test/run-pass/resource-in-struct.rs +++ b/src/test/run-pass/resource-in-struct.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/return-from-closure.rs b/src/test/run-pass/return-from-closure.rs index 4395f6fcb4b7c..76eddd05382fc 100644 --- a/src/test/run-pass/return-from-closure.rs +++ b/src/test/run-pass/return-from-closure.rs @@ -10,7 +10,6 @@ // just to make sure that `return` is only returning from the closure, // not the surrounding function. -// pretty-expanded FIXME #23616 static mut calls: usize = 0; diff --git a/src/test/run-pass/segfault-no-out-of-stack.rs b/src/test/run-pass/segfault-no-out-of-stack.rs index 6eb9600cf8b53..385c5326c978e 100644 --- a/src/test/run-pass/segfault-no-out-of-stack.rs +++ b/src/test/run-pass/segfault-no-out-of-stack.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(old_io)] diff --git a/src/test/run-pass/self-in-mut-slot-default-method.rs b/src/test/run-pass/self-in-mut-slot-default-method.rs index f8502137be129..877988e60a946 100644 --- a/src/test/run-pass/self-in-mut-slot-default-method.rs +++ b/src/test/run-pass/self-in-mut-slot-default-method.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/self-in-mut-slot-immediate-value.rs b/src/test/run-pass/self-in-mut-slot-immediate-value.rs index fa9ad9f6517a6..24014c289f919 100644 --- a/src/test/run-pass/self-in-mut-slot-immediate-value.rs +++ b/src/test/run-pass/self-in-mut-slot-immediate-value.rs @@ -11,7 +11,6 @@ // Assert that `mut self` on an immediate value doesn't // allow mutating the original - issue #10615. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] struct Value { diff --git a/src/test/run-pass/self-re-assign.rs b/src/test/run-pass/self-re-assign.rs index b3c81cab3c1ce..7314a65b60c0a 100644 --- a/src/test/run-pass/self-re-assign.rs +++ b/src/test/run-pass/self-re-assign.rs @@ -11,7 +11,6 @@ // Ensure assigning an owned or managed variable to itself works. In particular, // that we do not glue_drop before we glue_take (#3290). -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/self-shadowing-import.rs b/src/test/run-pass/self-shadowing-import.rs index 5de1686ef9d8d..cd47a0e86bda4 100644 --- a/src/test/run-pass/self-shadowing-import.rs +++ b/src/test/run-pass/self-shadowing-import.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod a { pub mod b { diff --git a/src/test/run-pass/send_str_hashmap.rs b/src/test/run-pass/send_str_hashmap.rs index 16a695f08fe6e..2501ef94bea82 100644 --- a/src/test/run-pass/send_str_hashmap.rs +++ b/src/test/run-pass/send_str_hashmap.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections, into_cow)] diff --git a/src/test/run-pass/send_str_treemap.rs b/src/test/run-pass/send_str_treemap.rs index d56657ee4d517..146f5253508c6 100644 --- a/src/test/run-pass/send_str_treemap.rs +++ b/src/test/run-pass/send_str_treemap.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections, into_cow)] diff --git a/src/test/run-pass/sendfn-is-a-block.rs b/src/test/run-pass/sendfn-is-a-block.rs index 59b92ec6a48da..162b05f0bb3f5 100644 --- a/src/test/run-pass/sendfn-is-a-block.rs +++ b/src/test/run-pass/sendfn-is-a-block.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn test(f: F) -> usize where F: FnOnce(usize) -> usize { return f(22); diff --git a/src/test/run-pass/sepcomp-cci.rs b/src/test/run-pass/sepcomp-cci.rs index a4d74dbd55ae1..a1c5ad113c76d 100644 --- a/src/test/run-pass/sepcomp-cci.rs +++ b/src/test/run-pass/sepcomp-cci.rs @@ -14,7 +14,6 @@ // Test accessing cross-crate inlined items from multiple compilation units. -// pretty-expanded FIXME #23616 extern crate sepcomp_cci_lib; use sepcomp_cci_lib::{cci_fn, CCI_STATIC}; diff --git a/src/test/run-pass/sepcomp-extern.rs b/src/test/run-pass/sepcomp-extern.rs index 3ec27466f4ced..973c61712c3ed 100644 --- a/src/test/run-pass/sepcomp-extern.rs +++ b/src/test/run-pass/sepcomp-extern.rs @@ -14,7 +14,6 @@ // Test accessing external items from multiple compilation units. -// pretty-expanded FIXME #23616 #[link(name = "sepcomp_extern_lib")] extern { diff --git a/src/test/run-pass/sepcomp-fns-backwards.rs b/src/test/run-pass/sepcomp-fns-backwards.rs index cd101bb20642f..1ab8bc7f88c53 100644 --- a/src/test/run-pass/sepcomp-fns-backwards.rs +++ b/src/test/run-pass/sepcomp-fns-backwards.rs @@ -16,7 +16,6 @@ // Generate some code in the first compilation unit before declaring any // modules. This ensures that the first module doesn't go into the same // compilation unit as the top-level module. -// pretty-expanded FIXME #23616 fn pad() -> usize { 0 } diff --git a/src/test/run-pass/sepcomp-fns.rs b/src/test/run-pass/sepcomp-fns.rs index b76c24bfc18b5..a2356cf02a11f 100644 --- a/src/test/run-pass/sepcomp-fns.rs +++ b/src/test/run-pass/sepcomp-fns.rs @@ -18,7 +18,6 @@ // Generate some code in the first compilation unit before declaring any // modules. This ensures that the first module doesn't go into the same // compilation unit as the top-level module. -// pretty-expanded FIXME #23616 fn one() -> usize { 1 } diff --git a/src/test/run-pass/sepcomp-lib.rs b/src/test/run-pass/sepcomp-lib.rs index 00e83a570579d..abe842a332d8f 100644 --- a/src/test/run-pass/sepcomp-lib.rs +++ b/src/test/run-pass/sepcomp-lib.rs @@ -12,7 +12,6 @@ // Test linking against a library built with -C codegen-units > 1 -// pretty-expanded FIXME #23616 extern crate sepcomp_lib; use sepcomp_lib::a::one; diff --git a/src/test/run-pass/sepcomp-statics.rs b/src/test/run-pass/sepcomp-statics.rs index f10f25a58bf7e..8cda469a88bf5 100644 --- a/src/test/run-pass/sepcomp-statics.rs +++ b/src/test/run-pass/sepcomp-statics.rs @@ -13,7 +13,6 @@ // Test references to static items across compilation units. -// pretty-expanded FIXME #23616 fn pad() -> usize { 0 } diff --git a/src/test/run-pass/sepcomp-unwind.rs b/src/test/run-pass/sepcomp-unwind.rs index 9663679d09a7e..766e2b6b7228f 100644 --- a/src/test/run-pass/sepcomp-unwind.rs +++ b/src/test/run-pass/sepcomp-unwind.rs @@ -20,7 +20,6 @@ // In any case, this test should let us know if enabling parallel codegen ever // breaks unwinding. -// pretty-expanded FIXME #23616 use std::thread; diff --git a/src/test/run-pass/seq-compare.rs b/src/test/run-pass/seq-compare.rs index 743f54abcfa66..f1a21d90ab2dc 100644 --- a/src/test/run-pass/seq-compare.rs +++ b/src/test/run-pass/seq-compare.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { assert!(("hello".to_string() < "hellr".to_string())); diff --git a/src/test/run-pass/shift-various-types.rs b/src/test/run-pass/shift-various-types.rs index b0ab72c650d74..9238112a0818f 100644 --- a/src/test/run-pass/shift-various-types.rs +++ b/src/test/run-pass/shift-various-types.rs @@ -10,7 +10,6 @@ // Test that we can do shifts by any integral type. -// pretty-expanded FIXME #23616 struct Panolpy { i8: i8, diff --git a/src/test/run-pass/shift.rs b/src/test/run-pass/shift.rs index f1637fe1e0931..2f417e0e2f4e8 100644 --- a/src/test/run-pass/shift.rs +++ b/src/test/run-pass/shift.rs @@ -11,7 +11,6 @@ // Testing shifts for various combinations of integers // Issue #1570 -// pretty-expanded FIXME #23616 pub fn main() { test_misc(); diff --git a/src/test/run-pass/signed-shift-const-eval.rs b/src/test/run-pass/signed-shift-const-eval.rs index 7167236438088..9ea2dedcba17d 100644 --- a/src/test/run-pass/signed-shift-const-eval.rs +++ b/src/test/run-pass/signed-shift-const-eval.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum test { thing = -5 >> 1_usize } pub fn main() { diff --git a/src/test/run-pass/sigpipe-should-be-ignored.rs b/src/test/run-pass/sigpipe-should-be-ignored.rs index 4a05b487ae24e..7734a2e80c3c4 100644 --- a/src/test/run-pass/sigpipe-should-be-ignored.rs +++ b/src/test/run-pass/sigpipe-should-be-ignored.rs @@ -12,7 +12,6 @@ // doesn't die in a ball of fire, but rather it's gracefully handled. // ignore-aarch64 -// pretty-expanded FIXME #23616 use std::env; use std::io::prelude::*; diff --git a/src/test/run-pass/simd-binop.rs b/src/test/run-pass/simd-binop.rs index 9f7b78e4e3354..3ebf2a87361f6 100644 --- a/src/test/run-pass/simd-binop.rs +++ b/src/test/run-pass/simd-binop.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/simd-generics.rs b/src/test/run-pass/simd-generics.rs index 867f028a3fb3c..0e3d6b83a4be6 100644 --- a/src/test/run-pass/simd-generics.rs +++ b/src/test/run-pass/simd-generics.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(simd)] diff --git a/src/test/run-pass/simd-size-align.rs b/src/test/run-pass/simd-size-align.rs index 8324efc641727..025b2a77375e8 100644 --- a/src/test/run-pass/simd-size-align.rs +++ b/src/test/run-pass/simd-size-align.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(simd)] #![allow(non_camel_case_types)] diff --git a/src/test/run-pass/slice-2.rs b/src/test/run-pass/slice-2.rs index 7f34b94ad04b0..4762470a74735 100644 --- a/src/test/run-pass/slice-2.rs +++ b/src/test/run-pass/slice-2.rs @@ -10,7 +10,6 @@ // Test slicing expressions on slices and Vecs. -// pretty-expanded FIXME #23616 fn main() { let x: &[isize] = &[1, 2, 3, 4, 5]; diff --git a/src/test/run-pass/slice-panic-1.rs b/src/test/run-pass/slice-panic-1.rs index a4f737f74619c..854b03f917866 100644 --- a/src/test/run-pass/slice-panic-1.rs +++ b/src/test/run-pass/slice-panic-1.rs @@ -10,7 +10,6 @@ // Test that if a slicing expr[..] fails, the correct cleanups happen. -// pretty-expanded FIXME #23616 use std::thread; diff --git a/src/test/run-pass/slice-panic-2.rs b/src/test/run-pass/slice-panic-2.rs index f02a84b9070bf..42a19342884b0 100644 --- a/src/test/run-pass/slice-panic-2.rs +++ b/src/test/run-pass/slice-panic-2.rs @@ -10,7 +10,6 @@ // Test that if a slicing expr[..] fails, the correct cleanups happen. -// pretty-expanded FIXME #23616 use std::thread; diff --git a/src/test/run-pass/slice.rs b/src/test/run-pass/slice.rs index edc5f6b184624..60160bd668fa6 100644 --- a/src/test/run-pass/slice.rs +++ b/src/test/run-pass/slice.rs @@ -10,7 +10,6 @@ // Test slicing sugar. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/small-enum-range-edge.rs b/src/test/run-pass/small-enum-range-edge.rs index 9515da6fcbc8d..56abdf6e20a72 100644 --- a/src/test/run-pass/small-enum-range-edge.rs +++ b/src/test/run-pass/small-enum-range-edge.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 // this is for the wrapping_add call below. #![feature(core)] diff --git a/src/test/run-pass/spawn-types.rs b/src/test/run-pass/spawn-types.rs index aab292a940afb..ae4fabd34d629 100644 --- a/src/test/run-pass/spawn-types.rs +++ b/src/test/run-pass/spawn-types.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 /* Make sure we can spawn tasks that take different types of diff --git a/src/test/run-pass/stable-addr-of.rs b/src/test/run-pass/stable-addr-of.rs index f93600195dc25..5ffceb2c6a8bc 100644 --- a/src/test/run-pass/stable-addr-of.rs +++ b/src/test/run-pass/stable-addr-of.rs @@ -10,7 +10,6 @@ // Issue #2040 -// pretty-expanded FIXME #23616 pub fn main() { let foo: isize = 1; diff --git a/src/test/run-pass/static-function-pointer-xc.rs b/src/test/run-pass/static-function-pointer-xc.rs index 55f3b0883b9d9..a09928bd2208f 100644 --- a/src/test/run-pass/static-function-pointer-xc.rs +++ b/src/test/run-pass/static-function-pointer-xc.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:static-function-pointer-aux.rs -// pretty-expanded FIXME #23616 extern crate static_function_pointer_aux as aux; diff --git a/src/test/run-pass/static-function-pointer.rs b/src/test/run-pass/static-function-pointer.rs index 67cc033f7cf75..be297524309d2 100644 --- a/src/test/run-pass/static-function-pointer.rs +++ b/src/test/run-pass/static-function-pointer.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn f(x: isize) -> isize { x } fn g(x: isize) -> isize { 2 * x } diff --git a/src/test/run-pass/static-impl.rs b/src/test/run-pass/static-impl.rs index aff2797c1acce..84bb1b871b97e 100644 --- a/src/test/run-pass/static-impl.rs +++ b/src/test/run-pass/static-impl.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 pub trait plus { fn plus(&self) -> isize; diff --git a/src/test/run-pass/static-method-in-trait-with-tps-intracrate.rs b/src/test/run-pass/static-method-in-trait-with-tps-intracrate.rs index 4ccb044bbd2ca..c2b3a9a72283b 100644 --- a/src/test/run-pass/static-method-in-trait-with-tps-intracrate.rs +++ b/src/test/run-pass/static-method-in-trait-with-tps-intracrate.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Deserializer { fn read_int(&self) -> isize; diff --git a/src/test/run-pass/static-method-xcrate.rs b/src/test/run-pass/static-method-xcrate.rs index d0b69b430a692..57609cec9f2b0 100644 --- a/src/test/run-pass/static-method-xcrate.rs +++ b/src/test/run-pass/static-method-xcrate.rs @@ -10,7 +10,6 @@ // aux-build:static-methods-crate.rs -// pretty-expanded FIXME #23616 extern crate static_methods_crate; diff --git a/src/test/run-pass/static-methods-in-traits.rs b/src/test/run-pass/static-methods-in-traits.rs index cb23feb05a59d..3fd3bbe936fff 100644 --- a/src/test/run-pass/static-methods-in-traits.rs +++ b/src/test/run-pass/static-methods-in-traits.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod a { pub trait Foo { diff --git a/src/test/run-pass/static-mut-foreign.rs b/src/test/run-pass/static-mut-foreign.rs index c6b919c9738d4..b916a1ae2be7d 100644 --- a/src/test/run-pass/static-mut-foreign.rs +++ b/src/test/run-pass/static-mut-foreign.rs @@ -12,7 +12,6 @@ // statics cannot. This ensures that there's some form of error if this is // attempted. -// pretty-expanded FIXME #23616 #![feature(libc)] diff --git a/src/test/run-pass/static-mut-xc.rs b/src/test/run-pass/static-mut-xc.rs index 0456d17bdc4b4..c819db9454796 100644 --- a/src/test/run-pass/static-mut-xc.rs +++ b/src/test/run-pass/static-mut-xc.rs @@ -14,7 +14,6 @@ // aux-build:static_mut_xc.rs -// pretty-expanded FIXME #23616 extern crate static_mut_xc; diff --git a/src/test/run-pass/str-multiline.rs b/src/test/run-pass/str-multiline.rs index 0d0d56fcafb0b..94e14290498b8 100644 --- a/src/test/run-pass/str-multiline.rs +++ b/src/test/run-pass/str-multiline.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let a: String = "this \ diff --git a/src/test/run-pass/string-escapes.rs b/src/test/run-pass/string-escapes.rs index e0fc1c4ce46a7..1d13e531004c8 100644 --- a/src/test/run-pass/string-escapes.rs +++ b/src/test/run-pass/string-escapes.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { let x = "\\\\\ diff --git a/src/test/run-pass/struct-aliases-xcrate.rs b/src/test/run-pass/struct-aliases-xcrate.rs index 17cb8acea6fad..2ca9d599d84a0 100644 --- a/src/test/run-pass/struct-aliases-xcrate.rs +++ b/src/test/run-pass/struct-aliases-xcrate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:xcrate_struct_aliases.rs -// pretty-expanded FIXME #23616 extern crate xcrate_struct_aliases; diff --git a/src/test/run-pass/struct-aliases.rs b/src/test/run-pass/struct-aliases.rs index 79e7960cfb27c..7107243d760a4 100644 --- a/src/test/run-pass/struct-aliases.rs +++ b/src/test/run-pass/struct-aliases.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct S { x: isize, diff --git a/src/test/run-pass/struct-destructuring-cross-crate.rs b/src/test/run-pass/struct-destructuring-cross-crate.rs index 5fed712bd663a..63e8d694ddb56 100644 --- a/src/test/run-pass/struct-destructuring-cross-crate.rs +++ b/src/test/run-pass/struct-destructuring-cross-crate.rs @@ -10,7 +10,6 @@ // aux-build:struct_destructuring_cross_crate.rs -// pretty-expanded FIXME #23616 extern crate struct_destructuring_cross_crate; diff --git a/src/test/run-pass/struct-like-variant-match.rs b/src/test/run-pass/struct-like-variant-match.rs index f072d315d72bf..175090eadd982 100644 --- a/src/test/run-pass/struct-like-variant-match.rs +++ b/src/test/run-pass/struct-like-variant-match.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum Foo { Bar { diff --git a/src/test/run-pass/struct-new-as-field-name.rs b/src/test/run-pass/struct-new-as-field-name.rs index 73f27448f81a4..7fb3a64e02b88 100644 --- a/src/test/run-pass/struct-new-as-field-name.rs +++ b/src/test/run-pass/struct-new-as-field-name.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Foo { new: isize, diff --git a/src/test/run-pass/struct-order-of-eval-1.rs b/src/test/run-pass/struct-order-of-eval-1.rs index 49ec695a1228b..b5e4011bbea58 100644 --- a/src/test/run-pass/struct-order-of-eval-1.rs +++ b/src/test/run-pass/struct-order-of-eval-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct S { f0: String, f1: isize } diff --git a/src/test/run-pass/struct-order-of-eval-2.rs b/src/test/run-pass/struct-order-of-eval-2.rs index 45755608ff56a..7ec28f597edbe 100644 --- a/src/test/run-pass/struct-order-of-eval-2.rs +++ b/src/test/run-pass/struct-order-of-eval-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct S { f0: String, diff --git a/src/test/run-pass/struct-order-of-eval-3.rs b/src/test/run-pass/struct-order-of-eval-3.rs index 37b6de8e17ef1..60f9c4465a01c 100644 --- a/src/test/run-pass/struct-order-of-eval-3.rs +++ b/src/test/run-pass/struct-order-of-eval-3.rs @@ -11,7 +11,6 @@ // Checks that functional-record-update order-of-eval is as expected // even when no Drop-implementations are involved. -// pretty-expanded FIXME #23616 use std::sync::atomic::{Ordering, AtomicUsize, ATOMIC_USIZE_INIT}; diff --git a/src/test/run-pass/struct-order-of-eval-4.rs b/src/test/run-pass/struct-order-of-eval-4.rs index 1b53895f7d1a7..23a7e1ea71b8b 100644 --- a/src/test/run-pass/struct-order-of-eval-4.rs +++ b/src/test/run-pass/struct-order-of-eval-4.rs @@ -11,7 +11,6 @@ // Checks that struct-literal expression order-of-eval is as expected // even when no Drop-implementations are involved. -// pretty-expanded FIXME #23616 use std::sync::atomic::{Ordering, AtomicUsize, ATOMIC_USIZE_INIT}; diff --git a/src/test/run-pass/struct_variant_xc_match.rs b/src/test/run-pass/struct_variant_xc_match.rs index f43dd2332a17a..3ceb65bcfdeb1 100644 --- a/src/test/run-pass/struct_variant_xc_match.rs +++ b/src/test/run-pass/struct_variant_xc_match.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:struct_variant_xc_aux.rs -// pretty-expanded FIXME #23616 extern crate struct_variant_xc_aux; diff --git a/src/test/run-pass/supertrait-default-generics.rs b/src/test/run-pass/supertrait-default-generics.rs index 351c4259b5ef3..e014ce1966bc5 100644 --- a/src/test/run-pass/supertrait-default-generics.rs +++ b/src/test/run-pass/supertrait-default-generics.rs @@ -10,7 +10,6 @@ // There is some other borrowck bug, so we make the stuff not mut. -// pretty-expanded FIXME #23616 use std::ops::Add; diff --git a/src/test/run-pass/swap-1.rs b/src/test/run-pass/swap-1.rs index e60c672f00f9b..d84ee104514d6 100644 --- a/src/test/run-pass/swap-1.rs +++ b/src/test/run-pass/swap-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::swap; diff --git a/src/test/run-pass/swap-2.rs b/src/test/run-pass/swap-2.rs index 3891376e463c7..3dbd7f1a60126 100644 --- a/src/test/run-pass/swap-2.rs +++ b/src/test/run-pass/swap-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::swap; diff --git a/src/test/run-pass/syntax-extension-cfg.rs b/src/test/run-pass/syntax-extension-cfg.rs index 8766cba5dbb45..c1d8713b20e6b 100644 --- a/src/test/run-pass/syntax-extension-cfg.rs +++ b/src/test/run-pass/syntax-extension-cfg.rs @@ -10,7 +10,6 @@ // compile-flags: --cfg foo --cfg qux="foo" -// pretty-expanded FIXME #23616 pub fn main() { // check diff --git a/src/test/run-pass/tag-align-dyn-u64.rs b/src/test/run-pass/tag-align-dyn-u64.rs index a9f5875023f18..aaac1869af54f 100644 --- a/src/test/run-pass/tag-align-dyn-u64.rs +++ b/src/test/run-pass/tag-align-dyn-u64.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/tag-align-dyn-variants.rs b/src/test/run-pass/tag-align-dyn-variants.rs index 90b583e2e5072..1c3fb209e35a3 100644 --- a/src/test/run-pass/tag-align-dyn-variants.rs +++ b/src/test/run-pass/tag-align-dyn-variants.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/tag-align-u64.rs b/src/test/run-pass/tag-align-u64.rs index e922ac3b4668e..43485a5bfcb63 100644 --- a/src/test/run-pass/tag-align-u64.rs +++ b/src/test/run-pass/tag-align-u64.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/tag-variant-disr-val.rs b/src/test/run-pass/tag-variant-disr-val.rs index a063801032e3d..6dc69656759de 100644 --- a/src/test/run-pass/tag-variant-disr-val.rs +++ b/src/test/run-pass/tag-variant-disr-val.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use color::{red, green, blue, black, white, imaginary, purple, orange}; diff --git a/src/test/run-pass/tag.rs b/src/test/run-pass/tag.rs index dbd65ee6bd483..e3cfceb0d426f 100644 --- a/src/test/run-pass/tag.rs +++ b/src/test/run-pass/tag.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 enum colour { red(isize, isize), green, } diff --git a/src/test/run-pass/tail-direct.rs b/src/test/run-pass/tail-direct.rs index 01fc18af34332..4a7a0acdfa891 100644 --- a/src/test/run-pass/tail-direct.rs +++ b/src/test/run-pass/tail-direct.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { assert!((even(42))); assert!((odd(45))); } diff --git a/src/test/run-pass/task-comm-5.rs b/src/test/run-pass/task-comm-5.rs index cd3d97b88bade..cd5cb677d460b 100644 --- a/src/test/run-pass/task-comm-5.rs +++ b/src/test/run-pass/task-comm-5.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::sync::mpsc::channel; diff --git a/src/test/run-pass/task-comm-6.rs b/src/test/run-pass/task-comm-6.rs index 80e777d242cfc..b8b5773ade546 100644 --- a/src/test/run-pass/task-comm-6.rs +++ b/src/test/run-pass/task-comm-6.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(dead_assignment)] diff --git a/src/test/run-pass/task-comm-chan-nil.rs b/src/test/run-pass/task-comm-chan-nil.rs index 77571504fea27..3b9ec42169150 100644 --- a/src/test/run-pass/task-comm-chan-nil.rs +++ b/src/test/run-pass/task-comm-chan-nil.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::sync::mpsc::channel; diff --git a/src/test/run-pass/terminate-in-initializer.rs b/src/test/run-pass/terminate-in-initializer.rs index ec9e7de40dce1..83eb351df530f 100644 --- a/src/test/run-pass/terminate-in-initializer.rs +++ b/src/test/run-pass/terminate-in-initializer.rs @@ -12,7 +12,6 @@ // Issue #787 // Don't try to clean up uninitialized locals -// pretty-expanded FIXME #23616 use std::thread; diff --git a/src/test/run-pass/trait-bounds.rs b/src/test/run-pass/trait-bounds.rs index 642119df15cbf..d501fef122cc7 100644 --- a/src/test/run-pass/trait-bounds.rs +++ b/src/test/run-pass/trait-bounds.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait connection { fn read(&self) -> isize; diff --git a/src/test/run-pass/trait-default-method-bound-subst.rs b/src/test/run-pass/trait-default-method-bound-subst.rs index e936989537e0f..b9936bcadd48d 100644 --- a/src/test/run-pass/trait-default-method-bound-subst.rs +++ b/src/test/run-pass/trait-default-method-bound-subst.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait A { fn g(&self, x: T, y: U) -> (T, U) { (x, y) } diff --git a/src/test/run-pass/trait-default-method-bound-subst2.rs b/src/test/run-pass/trait-default-method-bound-subst2.rs index 4fedbba81f41a..92b9449461ba1 100644 --- a/src/test/run-pass/trait-default-method-bound-subst2.rs +++ b/src/test/run-pass/trait-default-method-bound-subst2.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait A { fn g(&self, x: T) -> T { x } diff --git a/src/test/run-pass/trait-default-method-bound-subst3.rs b/src/test/run-pass/trait-default-method-bound-subst3.rs index 4f749cbd3fdbd..af7e8830332b0 100644 --- a/src/test/run-pass/trait-default-method-bound-subst3.rs +++ b/src/test/run-pass/trait-default-method-bound-subst3.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait A { fn g(&self, x: T, y: T) -> (T, T) { (x, y) } diff --git a/src/test/run-pass/trait-default-method-bound-subst4.rs b/src/test/run-pass/trait-default-method-bound-subst4.rs index 6774569cd252a..581a54e57f490 100644 --- a/src/test/run-pass/trait-default-method-bound-subst4.rs +++ b/src/test/run-pass/trait-default-method-bound-subst4.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait A { fn g(&self, x: usize) -> usize { x } diff --git a/src/test/run-pass/trait-default-method-bound.rs b/src/test/run-pass/trait-default-method-bound.rs index 4107540a47145..e0ea9651f6139 100644 --- a/src/test/run-pass/trait-default-method-bound.rs +++ b/src/test/run-pass/trait-default-method-bound.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait A { fn g(&self) -> isize { 10 } diff --git a/src/test/run-pass/trait-default-method-xc-2.rs b/src/test/run-pass/trait-default-method-xc-2.rs index d4ed727040016..833063d2a2d0e 100644 --- a/src/test/run-pass/trait-default-method-xc-2.rs +++ b/src/test/run-pass/trait-default-method-xc-2.rs @@ -12,7 +12,6 @@ // aux-build:trait_default_method_xc_aux_2.rs -// pretty-expanded FIXME #23616 extern crate trait_default_method_xc_aux as aux; extern crate trait_default_method_xc_aux_2 as aux2; diff --git a/src/test/run-pass/trait-default-method-xc.rs b/src/test/run-pass/trait-default-method-xc.rs index 65e8c53a25ec5..72e3fb256ca83 100644 --- a/src/test/run-pass/trait-default-method-xc.rs +++ b/src/test/run-pass/trait-default-method-xc.rs @@ -10,7 +10,6 @@ // aux-build:trait_default_method_xc_aux.rs -// pretty-expanded FIXME #23616 extern crate trait_default_method_xc_aux as aux; use aux::{A, TestEquality, Something}; diff --git a/src/test/run-pass/trait-generic.rs b/src/test/run-pass/trait-generic.rs index 6ef0dacee746a..4998236629153 100644 --- a/src/test/run-pass/trait-generic.rs +++ b/src/test/run-pass/trait-generic.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 trait to_str { fn to_string_(&self) -> String; diff --git a/src/test/run-pass/trait-impl.rs b/src/test/run-pass/trait-impl.rs index 95fd7bda474ba..10025a76f798f 100644 --- a/src/test/run-pass/trait-impl.rs +++ b/src/test/run-pass/trait-impl.rs @@ -11,7 +11,6 @@ // Test calling methods on an impl for a bare trait. // aux-build:traitimpl.rs -// pretty-expanded FIXME #23616 extern crate traitimpl; use traitimpl::Bar; diff --git a/src/test/run-pass/trait-inheritance-auto-xc-2.rs b/src/test/run-pass/trait-inheritance-auto-xc-2.rs index 128be2993ec1d..270cf652ed7cb 100644 --- a/src/test/run-pass/trait-inheritance-auto-xc-2.rs +++ b/src/test/run-pass/trait-inheritance-auto-xc-2.rs @@ -10,7 +10,6 @@ // aux-build:trait_inheritance_auto_xc_2_aux.rs -// pretty-expanded FIXME #23616 extern crate trait_inheritance_auto_xc_2_aux as aux; diff --git a/src/test/run-pass/trait-inheritance-auto-xc.rs b/src/test/run-pass/trait-inheritance-auto-xc.rs index 827674c81adc1..eaca60c935a60 100644 --- a/src/test/run-pass/trait-inheritance-auto-xc.rs +++ b/src/test/run-pass/trait-inheritance-auto-xc.rs @@ -10,7 +10,6 @@ // aux-build:trait_inheritance_auto_xc_aux.rs -// pretty-expanded FIXME #23616 extern crate trait_inheritance_auto_xc_aux as aux; diff --git a/src/test/run-pass/trait-inheritance-auto.rs b/src/test/run-pass/trait-inheritance-auto.rs index 1b72736cde439..75c48d5171278 100644 --- a/src/test/run-pass/trait-inheritance-auto.rs +++ b/src/test/run-pass/trait-inheritance-auto.rs @@ -10,7 +10,6 @@ // Testing that this impl turns A into a Quux, because // A is already a Foo Bar Baz -// pretty-expanded FIXME #23616 impl Quux for T { } diff --git a/src/test/run-pass/trait-inheritance-call-bound-inherited.rs b/src/test/run-pass/trait-inheritance-call-bound-inherited.rs index c8df12392faf4..2fb2b9274c699 100644 --- a/src/test/run-pass/trait-inheritance-call-bound-inherited.rs +++ b/src/test/run-pass/trait-inheritance-call-bound-inherited.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn f(&self) -> isize; } trait Bar : Foo { fn g(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs b/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs index fcd6143579c12..87dc04f1c6671 100644 --- a/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs +++ b/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn f(&self) -> isize; } trait Bar : Foo { fn g(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs b/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs index 3996ae850e84e..dd61dc0f9fb83 100644 --- a/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs +++ b/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs @@ -11,7 +11,6 @@ // Testing that we can cast to a subtrait and call subtrait // methods. Not testing supertrait methods -// pretty-expanded FIXME #23616 trait Foo { fn f(&self) -> isize; diff --git a/src/test/run-pass/trait-inheritance-cast.rs b/src/test/run-pass/trait-inheritance-cast.rs index 7784ed2f26ae9..0de2c586930e6 100644 --- a/src/test/run-pass/trait-inheritance-cast.rs +++ b/src/test/run-pass/trait-inheritance-cast.rs @@ -10,7 +10,6 @@ // Testing that supertrait methods can be called on subtrait object types -// pretty-expanded FIXME #23616 trait Foo { fn f(&self) -> isize; diff --git a/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs b/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs index c665c35b418c0..e1610c1db07fd 100644 --- a/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs +++ b/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs @@ -10,7 +10,6 @@ // aux-build:trait_inheritance_cross_trait_call_xc_aux.rs -// pretty-expanded FIXME #23616 extern crate trait_inheritance_cross_trait_call_xc_aux as aux; diff --git a/src/test/run-pass/trait-inheritance-cross-trait-call.rs b/src/test/run-pass/trait-inheritance-cross-trait-call.rs index 418986f961e58..27b0f66603f8c 100644 --- a/src/test/run-pass/trait-inheritance-cross-trait-call.rs +++ b/src/test/run-pass/trait-inheritance-cross-trait-call.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn f(&self) -> isize; } trait Bar : Foo { fn g(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance-diamond.rs b/src/test/run-pass/trait-inheritance-diamond.rs index 07b1a79110f63..43151bb0f9921 100644 --- a/src/test/run-pass/trait-inheritance-diamond.rs +++ b/src/test/run-pass/trait-inheritance-diamond.rs @@ -10,7 +10,6 @@ // B and C both require A, so D does as well, twice, but that's just fine -// pretty-expanded FIXME #23616 trait A { fn a(&self) -> isize; } trait B: A { fn b(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance-multiple-inheritors.rs b/src/test/run-pass/trait-inheritance-multiple-inheritors.rs index b89246269542e..8125ce20912e5 100644 --- a/src/test/run-pass/trait-inheritance-multiple-inheritors.rs +++ b/src/test/run-pass/trait-inheritance-multiple-inheritors.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait A { fn a(&self) -> isize; } trait B: A { fn b(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance-multiple-params.rs b/src/test/run-pass/trait-inheritance-multiple-params.rs index 37803edb752b1..c0f7a9d9c254a 100644 --- a/src/test/run-pass/trait-inheritance-multiple-params.rs +++ b/src/test/run-pass/trait-inheritance-multiple-params.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait A { fn a(&self) -> isize; } trait B: A { fn b(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs b/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs index f44c6927c87e0..21d6c53a465cf 100644 --- a/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs +++ b/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs @@ -10,7 +10,6 @@ // aux-build:trait_inheritance_overloading_xc.rs -// pretty-expanded FIXME #23616 extern crate trait_inheritance_overloading_xc; use trait_inheritance_overloading_xc::{MyNum, MyInt}; diff --git a/src/test/run-pass/trait-inheritance-self-in-supertype.rs b/src/test/run-pass/trait-inheritance-self-in-supertype.rs index 87a36ba7b90cc..ac9485594eb3e 100644 --- a/src/test/run-pass/trait-inheritance-self-in-supertype.rs +++ b/src/test/run-pass/trait-inheritance-self-in-supertype.rs @@ -10,7 +10,6 @@ // Test for issue #4183: use of Self in supertraits. -// pretty-expanded FIXME #23616 use std::num::Float as StdFloat; diff --git a/src/test/run-pass/trait-inheritance-simple.rs b/src/test/run-pass/trait-inheritance-simple.rs index ff89b1ee5d30d..917e520339af4 100644 --- a/src/test/run-pass/trait-inheritance-simple.rs +++ b/src/test/run-pass/trait-inheritance-simple.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn f(&self) -> isize; } trait Bar : Foo { fn g(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance-static.rs b/src/test/run-pass/trait-inheritance-static.rs index 9ed5fd0aaa53f..8e56582951154 100644 --- a/src/test/run-pass/trait-inheritance-static.rs +++ b/src/test/run-pass/trait-inheritance-static.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub trait MyNum { fn from_int(isize) -> Self; diff --git a/src/test/run-pass/trait-inheritance-static2.rs b/src/test/run-pass/trait-inheritance-static2.rs index 9fe9d7fce7af5..62feecf045b54 100644 --- a/src/test/run-pass/trait-inheritance-static2.rs +++ b/src/test/run-pass/trait-inheritance-static2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/trait-inheritance-subst.rs b/src/test/run-pass/trait-inheritance-subst.rs index d35a937a5733d..6074c8a71b0d0 100644 --- a/src/test/run-pass/trait-inheritance-subst.rs +++ b/src/test/run-pass/trait-inheritance-subst.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub trait Add { fn add(&self, rhs: &RHS) -> Result; diff --git a/src/test/run-pass/trait-inheritance-subst2.rs b/src/test/run-pass/trait-inheritance-subst2.rs index e0be5759503c6..6a3639954350f 100644 --- a/src/test/run-pass/trait-inheritance-subst2.rs +++ b/src/test/run-pass/trait-inheritance-subst2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Panda { fn chomp(&self, bamboo: &T) -> T; diff --git a/src/test/run-pass/trait-inheritance-visibility.rs b/src/test/run-pass/trait-inheritance-visibility.rs index 8c8b9232dee8c..f00a4f2ecb6aa 100644 --- a/src/test/run-pass/trait-inheritance-visibility.rs +++ b/src/test/run-pass/trait-inheritance-visibility.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod traits { pub trait Foo { fn f(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance2.rs b/src/test/run-pass/trait-inheritance2.rs index 9e721836d6319..2161c0f894f43 100644 --- a/src/test/run-pass/trait-inheritance2.rs +++ b/src/test/run-pass/trait-inheritance2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn f(&self) -> isize; } trait Bar { fn g(&self) -> isize; } diff --git a/src/test/run-pass/trait-object-generics.rs b/src/test/run-pass/trait-object-generics.rs index 63246b870cb59..15a8a2e83e340 100644 --- a/src/test/run-pass/trait-object-generics.rs +++ b/src/test/run-pass/trait-object-generics.rs @@ -10,7 +10,6 @@ // test for #8664 -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/trait-object-with-lifetime-bound.rs b/src/test/run-pass/trait-object-with-lifetime-bound.rs index 30a05ee1c562e..21b84221d06e0 100644 --- a/src/test/run-pass/trait-object-with-lifetime-bound.rs +++ b/src/test/run-pass/trait-object-with-lifetime-bound.rs @@ -11,7 +11,6 @@ // Uncovered during work on new scoping rules for safe destructors // as an important use case to support properly. -// pretty-expanded FIXME #23616 pub struct E<'a> { pub f: &'a u8, diff --git a/src/test/run-pass/trait-safety-ok-cc.rs b/src/test/run-pass/trait-safety-ok-cc.rs index ada79399561a9..abbc556f34e4c 100644 --- a/src/test/run-pass/trait-safety-ok-cc.rs +++ b/src/test/run-pass/trait-safety-ok-cc.rs @@ -12,7 +12,6 @@ // Simple smoke test that unsafe traits can be compiled across crates. -// pretty-expanded FIXME #23616 extern crate trait_safety_lib as lib; diff --git a/src/test/run-pass/trait-safety-ok.rs b/src/test/run-pass/trait-safety-ok.rs index 3cd23aeaf27a5..0ccc6cd152dfc 100644 --- a/src/test/run-pass/trait-safety-ok.rs +++ b/src/test/run-pass/trait-safety-ok.rs @@ -10,7 +10,6 @@ // Simple smoke test that unsafe traits can be compiled etc. -// pretty-expanded FIXME #23616 unsafe trait Foo { fn foo(&self) -> isize; diff --git a/src/test/run-pass/traits-assoc-type-in-supertrait.rs b/src/test/run-pass/traits-assoc-type-in-supertrait.rs index 751cd50441362..5cecacafc74b1 100644 --- a/src/test/run-pass/traits-assoc-type-in-supertrait.rs +++ b/src/test/run-pass/traits-assoc-type-in-supertrait.rs @@ -11,7 +11,6 @@ // Test case where an associated type is referenced from within the // supertrait definition. Issue #20220. -// pretty-expanded FIXME #23616 use std::vec::IntoIter; diff --git a/src/test/run-pass/traits-conditional-dispatch.rs b/src/test/run-pass/traits-conditional-dispatch.rs index 0a6b9da74f218..8d2faaf418b54 100644 --- a/src/test/run-pass/traits-conditional-dispatch.rs +++ b/src/test/run-pass/traits-conditional-dispatch.rs @@ -12,7 +12,6 @@ // blanket impl for T:Copy coexists with an impl for Box, because // Box does not impl Copy. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/traits-conditional-model-fn.rs b/src/test/run-pass/traits-conditional-model-fn.rs index 65a48844620de..d19f7143ed222 100644 --- a/src/test/run-pass/traits-conditional-model-fn.rs +++ b/src/test/run-pass/traits-conditional-model-fn.rs @@ -14,7 +14,6 @@ // aux-build:go_trait.rs -// pretty-expanded FIXME #23616 extern crate go_trait; diff --git a/src/test/run-pass/traits-default-method-macro.rs b/src/test/run-pass/traits-default-method-macro.rs index 1ec58eac58bbd..193038d9e50f3 100644 --- a/src/test/run-pass/traits-default-method-macro.rs +++ b/src/test/run-pass/traits-default-method-macro.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn bar(&self) -> String { diff --git a/src/test/run-pass/traits-multidispatch-infer-convert-target.rs b/src/test/run-pass/traits-multidispatch-infer-convert-target.rs index 1f1d1a46cf973..6634c1ad0a220 100644 --- a/src/test/run-pass/traits-multidispatch-infer-convert-target.rs +++ b/src/test/run-pass/traits-multidispatch-infer-convert-target.rs @@ -10,7 +10,6 @@ // Test that we can infer the Target based on the Self or vice versa. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/traits-repeated-supertrait.rs b/src/test/run-pass/traits-repeated-supertrait.rs index 509a6e36afdec..b059945ef74e3 100644 --- a/src/test/run-pass/traits-repeated-supertrait.rs +++ b/src/test/run-pass/traits-repeated-supertrait.rs @@ -13,7 +13,6 @@ // various methods in various ways successfully. // See also `compile-fail/trait-repeated-supertrait-ambig.rs`. -// pretty-expanded FIXME #23616 trait CompareTo { fn same_as(&self, t: T) -> bool; diff --git a/src/test/run-pass/trans-tag-static-padding.rs b/src/test/run-pass/trans-tag-static-padding.rs index 3e2297f008f02..ba01d51dc6a5d 100644 --- a/src/test/run-pass/trans-tag-static-padding.rs +++ b/src/test/run-pass/trans-tag-static-padding.rs @@ -21,7 +21,6 @@ // Last 7 bytes of Request struct are not occupied by any fields. -// pretty-expanded FIXME #23616 enum TestOption { TestNone, diff --git a/src/test/run-pass/tup.rs b/src/test/run-pass/tup.rs index 50687756e2abe..86ca37deb02d1 100644 --- a/src/test/run-pass/tup.rs +++ b/src/test/run-pass/tup.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 type point = (isize, isize); diff --git a/src/test/run-pass/tuple-index-fat-types.rs b/src/test/run-pass/tuple-index-fat-types.rs index 395531d1573a1..e4ea073bfc28a 100644 --- a/src/test/run-pass/tuple-index-fat-types.rs +++ b/src/test/run-pass/tuple-index-fat-types.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Foo<'a>(&'a [isize]); diff --git a/src/test/run-pass/tuple-index.rs b/src/test/run-pass/tuple-index.rs index a70b49296fa19..26d918f236750 100644 --- a/src/test/run-pass/tuple-index.rs +++ b/src/test/run-pass/tuple-index.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Point(isize, isize); diff --git a/src/test/run-pass/tydesc-name.rs b/src/test/run-pass/tydesc-name.rs index 4ba7e786ec8d2..1534c301c996c 100644 --- a/src/test/run-pass/tydesc-name.rs +++ b/src/test/run-pass/tydesc-name.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/type-id-higher-rank.rs b/src/test/run-pass/type-id-higher-rank.rs index ec5aa2863a0c5..3030833c7721d 100644 --- a/src/test/run-pass/type-id-higher-rank.rs +++ b/src/test/run-pass/type-id-higher-rank.rs @@ -11,7 +11,6 @@ // Test that type IDs correctly account for higher-rank lifetimes // Also acts as a regression test for an ICE (issue #19791) -// pretty-expanded FIXME #23616 #![feature(unboxed_closures, core)] diff --git a/src/test/run-pass/type-namespace.rs b/src/test/run-pass/type-namespace.rs index c03ddd0c649f5..36f8b2ca5b42a 100644 --- a/src/test/run-pass/type-namespace.rs +++ b/src/test/run-pass/type-namespace.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct A { a: isize } diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index 8c1251feea269..fc6499ce5d462 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::size_of; diff --git a/src/test/run-pass/typeck-macro-interaction-issue-8852.rs b/src/test/run-pass/typeck-macro-interaction-issue-8852.rs index 2da8b0a508ae4..696e151a80e8b 100644 --- a/src/test/run-pass/typeck-macro-interaction-issue-8852.rs +++ b/src/test/run-pass/typeck-macro-interaction-issue-8852.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum T { A(isize), diff --git a/src/test/run-pass/typeck_type_placeholder_1.rs b/src/test/run-pass/typeck_type_placeholder_1.rs index 53e78db68b19d..113d52ffb35b9 100644 --- a/src/test/run-pass/typeck_type_placeholder_1.rs +++ b/src/test/run-pass/typeck_type_placeholder_1.rs @@ -11,7 +11,6 @@ // This test checks that the `_` type placeholder works // correctly for enabling type inference. -// pretty-expanded FIXME #23616 struct TestStruct { x: *const isize diff --git a/src/test/run-pass/typeid-intrinsic.rs b/src/test/run-pass/typeid-intrinsic.rs index 7a143ce588915..9741ed0fddec8 100644 --- a/src/test/run-pass/typeid-intrinsic.rs +++ b/src/test/run-pass/typeid-intrinsic.rs @@ -11,7 +11,6 @@ // aux-build:typeid-intrinsic.rs // aux-build:typeid-intrinsic2.rs -// pretty-expanded FIXME #23616 #![feature(hash, core)] diff --git a/src/test/run-pass/typestate-multi-decl.rs b/src/test/run-pass/typestate-multi-decl.rs index c7762a8464d6b..0749b52a1c601 100644 --- a/src/test/run-pass/typestate-multi-decl.rs +++ b/src/test/run-pass/typestate-multi-decl.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let (x, y) = (10, 20); diff --git a/src/test/run-pass/u32-decr.rs b/src/test/run-pass/u32-decr.rs index 4955ac8a4be63..b56b6f32c0291 100644 --- a/src/test/run-pass/u32-decr.rs +++ b/src/test/run-pass/u32-decr.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let mut word: u32 = 200000; diff --git a/src/test/run-pass/u8-incr-decr.rs b/src/test/run-pass/u8-incr-decr.rs index 7c67d304edb68..d35ef015e6f0b 100644 --- a/src/test/run-pass/u8-incr-decr.rs +++ b/src/test/run-pass/u8-incr-decr.rs @@ -14,7 +14,6 @@ // These constants were chosen because they aren't used anywhere // in the rest of the generated code so they're easily grep-able. -// pretty-expanded FIXME #23616 pub fn main() { let mut x: u8 = 19; // 0x13 diff --git a/src/test/run-pass/u8-incr.rs b/src/test/run-pass/u8-incr.rs index e15576c3fabce..9554f9c2dfbca 100644 --- a/src/test/run-pass/u8-incr.rs +++ b/src/test/run-pass/u8-incr.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let mut x: u8 = 12; diff --git a/src/test/run-pass/ufcs-polymorphic-paths.rs b/src/test/run-pass/ufcs-polymorphic-paths.rs index a6ea0f76dc2f9..db3581976bbc3 100644 --- a/src/test/run-pass/ufcs-polymorphic-paths.rs +++ b/src/test/run-pass/ufcs-polymorphic-paths.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections, rand, into_cow)] diff --git a/src/test/run-pass/ufcs-trait-object.rs b/src/test/run-pass/ufcs-trait-object.rs index b242018458dfc..457beeb3f37a3 100644 --- a/src/test/run-pass/ufcs-trait-object.rs +++ b/src/test/run-pass/ufcs-trait-object.rs @@ -11,7 +11,6 @@ // Test that when you use ufcs form to invoke a trait method (on a // trait object) everything works fine. -// pretty-expanded FIXME #23616 trait Foo { fn test(&self) -> i32; diff --git a/src/test/run-pass/unboxed-closures-all-traits.rs b/src/test/run-pass/unboxed-closures-all-traits.rs index 9ca8e5403a130..c28d4f463e572 100644 --- a/src/test/run-pass/unboxed-closures-all-traits.rs +++ b/src/test/run-pass/unboxed-closures-all-traits.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(lang_items, unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs b/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs index 37dccca1e2245..54c92900c89bb 100644 --- a/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs +++ b/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs @@ -10,7 +10,6 @@ // Test that you can supply `&F` where `F: FnMut()`. -// pretty-expanded FIXME #23616 #![feature(lang_items, unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-blanket-fn.rs b/src/test/run-pass/unboxed-closures-blanket-fn.rs index 0f93966077bc3..eb474473094a2 100644 --- a/src/test/run-pass/unboxed-closures-blanket-fn.rs +++ b/src/test/run-pass/unboxed-closures-blanket-fn.rs @@ -10,7 +10,6 @@ // Test that you can supply `&F` where `F: Fn()`. -// pretty-expanded FIXME #23616 #![feature(lang_items, unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-by-ref.rs b/src/test/run-pass/unboxed-closures-by-ref.rs index 7855cf6ba0c2a..e3ddfdbac00f8 100644 --- a/src/test/run-pass/unboxed-closures-by-ref.rs +++ b/src/test/run-pass/unboxed-closures-by-ref.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs b/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs index 6e92850ac2e59..64236ce563b0e 100644 --- a/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs +++ b/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs @@ -10,7 +10,6 @@ // Test that the call operator autoderefs when calling a bounded type parameter. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs b/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs index 402b4b0b85d4b..67ab84f0276cc 100644 --- a/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs +++ b/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs @@ -10,7 +10,6 @@ // Test that the call operator autoderefs when calling a bounded type parameter. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-counter-not-moved.rs b/src/test/run-pass/unboxed-closures-counter-not-moved.rs index 792d17227766e..cb5f190bcd736 100644 --- a/src/test/run-pass/unboxed-closures-counter-not-moved.rs +++ b/src/test/run-pass/unboxed-closures-counter-not-moved.rs @@ -10,7 +10,6 @@ // Test that we mutate a counter on the stack only when we expect to. -// pretty-expanded FIXME #23616 fn call(f: F) where F : FnOnce() { f(); diff --git a/src/test/run-pass/unboxed-closures-cross-crate.rs b/src/test/run-pass/unboxed-closures-cross-crate.rs index 0c255c6bd6cb8..37dc760cedcfe 100644 --- a/src/test/run-pass/unboxed-closures-cross-crate.rs +++ b/src/test/run-pass/unboxed-closures-cross-crate.rs @@ -12,7 +12,6 @@ // Acts as a regression test for #16790, #18378 and #18543 // aux-build:unboxed-closures-cross-crate.rs -// pretty-expanded FIXME #23616 extern crate unboxed_closures_cross_crate as ubcc; diff --git a/src/test/run-pass/unboxed-closures-drop.rs b/src/test/run-pass/unboxed-closures-drop.rs index f0c6c0ff453ff..78f4905aef976 100644 --- a/src/test/run-pass/unboxed-closures-drop.rs +++ b/src/test/run-pass/unboxed-closures-drop.rs @@ -11,7 +11,6 @@ // A battery of tests to ensure destructors of unboxed closure environments // run at the right times. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-extern-fn-hr.rs b/src/test/run-pass/unboxed-closures-extern-fn-hr.rs index 4af4b320d0e4e..e71757abd0e7d 100644 --- a/src/test/run-pass/unboxed-closures-extern-fn-hr.rs +++ b/src/test/run-pass/unboxed-closures-extern-fn-hr.rs @@ -10,7 +10,6 @@ // Checks that higher-ranked extern fn pointers implement the full range of Fn traits. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures, core)] diff --git a/src/test/run-pass/unboxed-closures-extern-fn.rs b/src/test/run-pass/unboxed-closures-extern-fn.rs index d711ebbe4b8c2..57acbae4ce6d8 100644 --- a/src/test/run-pass/unboxed-closures-extern-fn.rs +++ b/src/test/run-pass/unboxed-closures-extern-fn.rs @@ -10,7 +10,6 @@ // Checks that extern fn pointers implement the full range of Fn traits. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs index 9b71abf365331..5d6d372ea5c95 100644 --- a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs @@ -11,7 +11,6 @@ // Checks that the Fn trait hierarchy rules permit // any Fn trait to be used where Fn is implemented. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures, core)] diff --git a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs index 6261058b86742..c19b5b273c7eb 100644 --- a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs @@ -11,7 +11,6 @@ // Checks that the Fn trait hierarchy rules permit // FnMut or FnOnce to be used where FnMut is implemented. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures, core)] diff --git a/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs b/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs index 798959f69d687..2da899ed95b5a 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs @@ -11,7 +11,6 @@ // Test that we are able to infer a suitable kind for this closure // that is just called (`FnMut`). -// pretty-expanded FIXME #23616 fn main() { let mut counter = 0; diff --git a/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs b/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs index 5b1e35a3e5c72..32fc3433e8477 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs @@ -11,7 +11,6 @@ // Test that we are able to infer a suitable kind for this `move` // closure that is just called (`FnMut`). -// pretty-expanded FIXME #23616 fn main() { let mut counter = 0; diff --git a/src/test/run-pass/unboxed-closures-infer-fnmut.rs b/src/test/run-pass/unboxed-closures-infer-fnmut.rs index cd7f26bba2676..a8469f4019ab1 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnmut.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnmut.rs @@ -11,7 +11,6 @@ // Test that we are able to infer a suitable kind for this closure // that is just called (`FnMut`). -// pretty-expanded FIXME #23616 fn main() { let mut counter = 0; diff --git a/src/test/run-pass/unboxed-closures-infer-fnonce-move.rs b/src/test/run-pass/unboxed-closures-infer-fnonce-move.rs index dc106614b53dd..dcda724c7b8fe 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnonce-move.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnonce-move.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/unboxed-closures-infer-fnonce.rs b/src/test/run-pass/unboxed-closures-infer-fnonce.rs index 036b32a44d255..275ba0520c568 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnonce.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/unboxed-closures-infer-kind.rs b/src/test/run-pass/unboxed-closures-infer-kind.rs index edc01d91f58fc..fa668475f587a 100644 --- a/src/test/run-pass/unboxed-closures-infer-kind.rs +++ b/src/test/run-pass/unboxed-closures-infer-kind.rs @@ -11,7 +11,6 @@ // Test that we can infer the "kind" of an unboxed closure based on // the expected type. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs b/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs index e02784f917a97..e499ab5cca06c 100644 --- a/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs +++ b/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core,unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-infer-upvar.rs b/src/test/run-pass/unboxed-closures-infer-upvar.rs index e29632b007b3f..f2423145b1974 100644 --- a/src/test/run-pass/unboxed-closures-infer-upvar.rs +++ b/src/test/run-pass/unboxed-closures-infer-upvar.rs @@ -11,7 +11,6 @@ // Test that the type variable in the type(`Vec<_>`) of a closed over // variable does not interfere with type inference. -// pretty-expanded FIXME #23616 fn f(mut f: F) { f(); diff --git a/src/test/run-pass/unboxed-closures-manual-impl.rs b/src/test/run-pass/unboxed-closures-manual-impl.rs index 38f15d6e4499b..6a76fdb5ad7e4 100644 --- a/src/test/run-pass/unboxed-closures-manual-impl.rs +++ b/src/test/run-pass/unboxed-closures-manual-impl.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures, core)] diff --git a/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs b/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs index b69153b73a369..e2b286738e76d 100644 --- a/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs +++ b/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs @@ -11,7 +11,6 @@ // Test that in a by-ref once closure we move some variables even as // we capture others by mutable reference. -// pretty-expanded FIXME #23616 fn call(f: F) where F : FnOnce() { f(); diff --git a/src/test/run-pass/unboxed-closures-simple.rs b/src/test/run-pass/unboxed-closures-simple.rs index 1443d305bce94..ec3419816693e 100644 --- a/src/test/run-pass/unboxed-closures-simple.rs +++ b/src/test/run-pass/unboxed-closures-simple.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-single-word-env.rs b/src/test/run-pass/unboxed-closures-single-word-env.rs index 65a26d14e120b..166054e88b7b3 100644 --- a/src/test/run-pass/unboxed-closures-single-word-env.rs +++ b/src/test/run-pass/unboxed-closures-single-word-env.rs @@ -11,7 +11,6 @@ // Ensures that single-word environments work right in unboxed closures. // These take a different path in codegen. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-sugar-object.rs b/src/test/run-pass/unboxed-closures-sugar-object.rs index 77beeb13fb029..49b9b7f061e72 100644 --- a/src/test/run-pass/unboxed-closures-sugar-object.rs +++ b/src/test/run-pass/unboxed-closures-sugar-object.rs @@ -10,7 +10,6 @@ // Test unboxed closure sugar used in object types. -// pretty-expanded FIXME #23616 #![allow(dead_code)] #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-unique-type-id.rs b/src/test/run-pass/unboxed-closures-unique-type-id.rs index 403b2ca9aaf39..de7eeb57de10d 100644 --- a/src/test/run-pass/unboxed-closures-unique-type-id.rs +++ b/src/test/run-pass/unboxed-closures-unique-type-id.rs @@ -19,7 +19,6 @@ // // compile-flags: -g -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unfold-cross-crate.rs b/src/test/run-pass/unfold-cross-crate.rs index fceccb499c7b0..5c699bf3044e6 100644 --- a/src/test/run-pass/unfold-cross-crate.rs +++ b/src/test/run-pass/unfold-cross-crate.rs @@ -10,7 +10,6 @@ // no-pretty-expanded FIXME #15189 -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/uniq-self-in-mut-slot.rs b/src/test/run-pass/uniq-self-in-mut-slot.rs index a6408128c3a28..baca157a488b7 100644 --- a/src/test/run-pass/uniq-self-in-mut-slot.rs +++ b/src/test/run-pass/uniq-self-in-mut-slot.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-assign-copy.rs b/src/test/run-pass/unique-assign-copy.rs index 32a0713ca9397..3323b3c046b11 100644 --- a/src/test/run-pass/unique-assign-copy.rs +++ b/src/test/run-pass/unique-assign-copy.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-assign-drop.rs b/src/test/run-pass/unique-assign-drop.rs index 715fa548a7d76..37aa1f0a64bc6 100644 --- a/src/test/run-pass/unique-assign-drop.rs +++ b/src/test/run-pass/unique-assign-drop.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(dead_assignment)] #![allow(unknown_features)] diff --git a/src/test/run-pass/unique-assign-generic.rs b/src/test/run-pass/unique-assign-generic.rs index ca145479a381f..249b734a691e0 100644 --- a/src/test/run-pass/unique-assign-generic.rs +++ b/src/test/run-pass/unique-assign-generic.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-assign.rs b/src/test/run-pass/unique-assign.rs index e4e7b69671b82..8e97fdd4a6af9 100644 --- a/src/test/run-pass/unique-assign.rs +++ b/src/test/run-pass/unique-assign.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-autoderef-field.rs b/src/test/run-pass/unique-autoderef-field.rs index 8ee1b28ea2e7e..a711dbb685f19 100644 --- a/src/test/run-pass/unique-autoderef-field.rs +++ b/src/test/run-pass/unique-autoderef-field.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-autoderef-index.rs b/src/test/run-pass/unique-autoderef-index.rs index 9dc98cf2e3c47..c68ff1f0612f5 100644 --- a/src/test/run-pass/unique-autoderef-index.rs +++ b/src/test/run-pass/unique-autoderef-index.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-cmp.rs b/src/test/run-pass/unique-cmp.rs index be7e46c8699d7..3b0ad63aeffe9 100644 --- a/src/test/run-pass/unique-cmp.rs +++ b/src/test/run-pass/unique-cmp.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-decl-init-copy.rs b/src/test/run-pass/unique-decl-init-copy.rs index 0840f1308cc1f..9d749803ffb16 100644 --- a/src/test/run-pass/unique-decl-init-copy.rs +++ b/src/test/run-pass/unique-decl-init-copy.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-decl-init.rs b/src/test/run-pass/unique-decl-init.rs index 1d5a44f45abba..a00de08998f4e 100644 --- a/src/test/run-pass/unique-decl-init.rs +++ b/src/test/run-pass/unique-decl-init.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-decl-move.rs b/src/test/run-pass/unique-decl-move.rs index 203a30e76bc1a..f4ff44ffff52c 100644 --- a/src/test/run-pass/unique-decl-move.rs +++ b/src/test/run-pass/unique-decl-move.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-decl.rs b/src/test/run-pass/unique-decl.rs index 7404e8887ebce..bbf9b2f47a742 100644 --- a/src/test/run-pass/unique-decl.rs +++ b/src/test/run-pass/unique-decl.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let _: Box; diff --git a/src/test/run-pass/unique-deref.rs b/src/test/run-pass/unique-deref.rs index 44681742a7041..70b2617797dae 100644 --- a/src/test/run-pass/unique-deref.rs +++ b/src/test/run-pass/unique-deref.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-destructure.rs b/src/test/run-pass/unique-destructure.rs index 87bc6f6639d65..b368cbee2f632 100644 --- a/src/test/run-pass/unique-destructure.rs +++ b/src/test/run-pass/unique-destructure.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_patterns)] diff --git a/src/test/run-pass/unique-fn-arg-move.rs b/src/test/run-pass/unique-fn-arg-move.rs index e608ab9b6367a..d101cbd31290c 100644 --- a/src/test/run-pass/unique-fn-arg-move.rs +++ b/src/test/run-pass/unique-fn-arg-move.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-fn-arg-mut.rs b/src/test/run-pass/unique-fn-arg-mut.rs index f0d2abfe27cbc..ebe89b275d4f7 100644 --- a/src/test/run-pass/unique-fn-arg-mut.rs +++ b/src/test/run-pass/unique-fn-arg-mut.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-fn-arg.rs b/src/test/run-pass/unique-fn-arg.rs index 3d7ef31d020e7..97006d2a01a2d 100644 --- a/src/test/run-pass/unique-fn-arg.rs +++ b/src/test/run-pass/unique-fn-arg.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-fn-ret.rs b/src/test/run-pass/unique-fn-ret.rs index bb1948bf3c81b..d3be0cf01f1dd 100644 --- a/src/test/run-pass/unique-fn-ret.rs +++ b/src/test/run-pass/unique-fn-ret.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-in-vec-copy.rs b/src/test/run-pass/unique-in-vec-copy.rs index 129c0784cca5e..ab0e3ee809dbd 100644 --- a/src/test/run-pass/unique-in-vec-copy.rs +++ b/src/test/run-pass/unique-in-vec-copy.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-in-vec.rs b/src/test/run-pass/unique-in-vec.rs index dc94fa6ca4fce..41945821587ca 100644 --- a/src/test/run-pass/unique-in-vec.rs +++ b/src/test/run-pass/unique-in-vec.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-kinds.rs b/src/test/run-pass/unique-kinds.rs index 96d54193ac86d..b808ac2b00823 100644 --- a/src/test/run-pass/unique-kinds.rs +++ b/src/test/run-pass/unique-kinds.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-move-drop.rs b/src/test/run-pass/unique-move-drop.rs index e81095d548e07..530ba4789102e 100644 --- a/src/test/run-pass/unique-move-drop.rs +++ b/src/test/run-pass/unique-move-drop.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unused_variable)] #![allow(unknown_features)] diff --git a/src/test/run-pass/unique-move-temp.rs b/src/test/run-pass/unique-move-temp.rs index 634a1569acffd..4b937625201c0 100644 --- a/src/test/run-pass/unique-move-temp.rs +++ b/src/test/run-pass/unique-move-temp.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-move.rs b/src/test/run-pass/unique-move.rs index 29bf113926572..bed1d6e171a8b 100644 --- a/src/test/run-pass/unique-move.rs +++ b/src/test/run-pass/unique-move.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-mutable.rs b/src/test/run-pass/unique-mutable.rs index 106481e3189ee..8beec6a419833 100644 --- a/src/test/run-pass/unique-mutable.rs +++ b/src/test/run-pass/unique-mutable.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-pat-2.rs b/src/test/run-pass/unique-pat-2.rs index d16355af99fd5..c314b70e53662 100644 --- a/src/test/run-pass/unique-pat-2.rs +++ b/src/test/run-pass/unique-pat-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_patterns)] diff --git a/src/test/run-pass/unique-pat.rs b/src/test/run-pass/unique-pat.rs index ae76179b5ec22..1312ea924b599 100644 --- a/src/test/run-pass/unique-pat.rs +++ b/src/test/run-pass/unique-pat.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_patterns)] diff --git a/src/test/run-pass/unique-rec.rs b/src/test/run-pass/unique-rec.rs index 7a09e241ca639..72975c27eeaf5 100644 --- a/src/test/run-pass/unique-rec.rs +++ b/src/test/run-pass/unique-rec.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-send-2.rs b/src/test/run-pass/unique-send-2.rs index 99a3b64105318..d80d0e82f4fe9 100644 --- a/src/test/run-pass/unique-send-2.rs +++ b/src/test/run-pass/unique-send-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-send.rs b/src/test/run-pass/unique-send.rs index c9649ef60d303..bc0f790b2b02d 100644 --- a/src/test/run-pass/unique-send.rs +++ b/src/test/run-pass/unique-send.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-swap.rs b/src/test/run-pass/unique-swap.rs index 454011a9ec31e..cfa076f1a0744 100644 --- a/src/test/run-pass/unique-swap.rs +++ b/src/test/run-pass/unique-swap.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unit-like-struct-drop-run.rs b/src/test/run-pass/unit-like-struct-drop-run.rs index c2db63ed251a5..e31d4c811fc63 100644 --- a/src/test/run-pass/unit-like-struct-drop-run.rs +++ b/src/test/run-pass/unit-like-struct-drop-run.rs @@ -10,7 +10,6 @@ // Make sure the destructor is run for unit-like structs. -// pretty-expanded FIXME #23616 #![feature(alloc)] diff --git a/src/test/run-pass/unreachable-code-1.rs b/src/test/run-pass/unreachable-code-1.rs index 612beabb03586..c1c069236c88d 100644 --- a/src/test/run-pass/unreachable-code-1.rs +++ b/src/test/run-pass/unreachable-code-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unreachable_code)] #![allow(unused_variable)] diff --git a/src/test/run-pass/unreachable-code.rs b/src/test/run-pass/unreachable-code.rs index 4f58df66256be..e19fda5f872d2 100644 --- a/src/test/run-pass/unreachable-code.rs +++ b/src/test/run-pass/unreachable-code.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(path_statement)] #![allow(unreachable_code)] diff --git a/src/test/run-pass/unsafe-coercion.rs b/src/test/run-pass/unsafe-coercion.rs index d0c633e8278ea..8661ebb414ce5 100644 --- a/src/test/run-pass/unsafe-coercion.rs +++ b/src/test/run-pass/unsafe-coercion.rs @@ -10,7 +10,6 @@ // Check that safe fns are not a subtype of unsafe fns. -// pretty-expanded FIXME #23616 fn foo(x: i32) -> i32 { x * 22 diff --git a/src/test/run-pass/unsafe-pointer-assignability.rs b/src/test/run-pass/unsafe-pointer-assignability.rs index 75c7cabfcb6d3..c8ee0f83b9b0c 100644 --- a/src/test/run-pass/unsafe-pointer-assignability.rs +++ b/src/test/run-pass/unsafe-pointer-assignability.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn f(x: *const isize) { unsafe { diff --git a/src/test/run-pass/unsized3.rs b/src/test/run-pass/unsized3.rs index 8db294bdcc1c0..2977f579fc592 100644 --- a/src/test/run-pass/unsized3.rs +++ b/src/test/run-pass/unsized3.rs @@ -10,7 +10,6 @@ // Test structs with always-unsized fields. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, core)] diff --git a/src/test/run-pass/unwind-unique.rs b/src/test/run-pass/unwind-unique.rs index 1d6ce626c28c5..07bfc8062f9d4 100644 --- a/src/test/run-pass/unwind-unique.rs +++ b/src/test/run-pass/unwind-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/variance-intersection-of-ref-and-opt-ref.rs b/src/test/run-pass/variance-intersection-of-ref-and-opt-ref.rs index e21ea025d8ff4..af06fe381368b 100644 --- a/src/test/run-pass/variance-intersection-of-ref-and-opt-ref.rs +++ b/src/test/run-pass/variance-intersection-of-ref-and-opt-ref.rs @@ -13,7 +13,6 @@ // us from approximating the lifetimes of `field1` and `field2` to a // common intersection. -// pretty-expanded FIXME #23616 #![allow(dead_code)] #![feature(core)] diff --git a/src/test/run-pass/variance-vec-covariant.rs b/src/test/run-pass/variance-vec-covariant.rs index 2f554c3c4f3f5..89927b7b55b97 100644 --- a/src/test/run-pass/variance-vec-covariant.rs +++ b/src/test/run-pass/variance-vec-covariant.rs @@ -10,7 +10,6 @@ // Test that vec is now covariant in its argument type. -// pretty-expanded FIXME #23616 #![allow(dead_code)] #![feature(core)] diff --git a/src/test/run-pass/vec-dst.rs b/src/test/run-pass/vec-dst.rs index e88acb3838ba8..223907c01bea3 100644 --- a/src/test/run-pass/vec-dst.rs +++ b/src/test/run-pass/vec-dst.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/vec-fixed-length.rs b/src/test/run-pass/vec-fixed-length.rs index 4dadf53c77222..fbaba9b8a6191 100644 --- a/src/test/run-pass/vec-fixed-length.rs +++ b/src/test/run-pass/vec-fixed-length.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::size_of; diff --git a/src/test/run-pass/vec-growth.rs b/src/test/run-pass/vec-growth.rs index d5e6a9c424515..e51d898e1d46e 100644 --- a/src/test/run-pass/vec-growth.rs +++ b/src/test/run-pass/vec-growth.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let mut v = vec!(1); diff --git a/src/test/run-pass/vec-macro-repeat.rs b/src/test/run-pass/vec-macro-repeat.rs index 2a83ccaba82e2..d178041b85e1e 100644 --- a/src/test/run-pass/vec-macro-repeat.rs +++ b/src/test/run-pass/vec-macro-repeat.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { assert_eq!(vec![1; 3], vec![1, 1, 1]); diff --git a/src/test/run-pass/vec-macro-rvalue-scope.rs b/src/test/run-pass/vec-macro-rvalue-scope.rs index 5869558eacaff..305755347d04b 100644 --- a/src/test/run-pass/vec-macro-rvalue-scope.rs +++ b/src/test/run-pass/vec-macro-rvalue-scope.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn one() -> i32 { 1 } diff --git a/src/test/run-pass/vec-macro-with-trailing-comma.rs b/src/test/run-pass/vec-macro-with-trailing-comma.rs index 3018a746b4a9d..35af249ef5fad 100644 --- a/src/test/run-pass/vec-macro-with-trailing-comma.rs +++ b/src/test/run-pass/vec-macro-with-trailing-comma.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { assert_eq!(vec!(1), vec!(1,)); diff --git a/src/test/run-pass/vec-matching-autoslice.rs b/src/test/run-pass/vec-matching-autoslice.rs index 2b80ad81037f2..5728424e32bb1 100644 --- a/src/test/run-pass/vec-matching-autoslice.rs +++ b/src/test/run-pass/vec-matching-autoslice.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-pass/vec-matching-fixed.rs b/src/test/run-pass/vec-matching-fixed.rs index 1278eaf96a48c..1ed6ddc411076 100644 --- a/src/test/run-pass/vec-matching-fixed.rs +++ b/src/test/run-pass/vec-matching-fixed.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] diff --git a/src/test/run-pass/vec-matching-fold.rs b/src/test/run-pass/vec-matching-fold.rs index c375fc85bc1d3..ee70ea58750d9 100644 --- a/src/test/run-pass/vec-matching-fold.rs +++ b/src/test/run-pass/vec-matching-fold.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] diff --git a/src/test/run-pass/vec-matching.rs b/src/test/run-pass/vec-matching.rs index b81bdda613f7c..eedf27f857700 100644 --- a/src/test/run-pass/vec-matching.rs +++ b/src/test/run-pass/vec-matching.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] diff --git a/src/test/run-pass/vec-slice-drop.rs b/src/test/run-pass/vec-slice-drop.rs index 1d749d4963c5e..f400869682fd2 100644 --- a/src/test/run-pass/vec-slice-drop.rs +++ b/src/test/run-pass/vec-slice-drop.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/vec-slice.rs b/src/test/run-pass/vec-slice.rs index 6baeb99df9e8c..a7e6cae93b34b 100644 --- a/src/test/run-pass/vec-slice.rs +++ b/src/test/run-pass/vec-slice.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let v = vec![1,2,3,4,5]; diff --git a/src/test/run-pass/vec-tail-matching.rs b/src/test/run-pass/vec-tail-matching.rs index 091e3f03e7ac7..75f970543a45a 100644 --- a/src/test/run-pass/vec-tail-matching.rs +++ b/src/test/run-pass/vec-tail-matching.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-pass/vec-to_str.rs b/src/test/run-pass/vec-to_str.rs index a9bb68395c425..f000ada770a40 100644 --- a/src/test/run-pass/vec-to_str.rs +++ b/src/test/run-pass/vec-to_str.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { assert_eq!(format!("{:?}", vec!(0, 1)), "[0, 1]".to_string()); diff --git a/src/test/run-pass/vec.rs b/src/test/run-pass/vec.rs index ce20d452c403c..c61b3d56dbfb9 100644 --- a/src/test/run-pass/vec.rs +++ b/src/test/run-pass/vec.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let v: Vec = vec!(10, 20); diff --git a/src/test/run-pass/vector-sort-panic-safe.rs b/src/test/run-pass/vector-sort-panic-safe.rs index eca7e62d67cbf..acb29d284b956 100644 --- a/src/test/run-pass/vector-sort-panic-safe.rs +++ b/src/test/run-pass/vector-sort-panic-safe.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(rand, core)] diff --git a/src/test/run-pass/wait-forked-but-failed-child.rs b/src/test/run-pass/wait-forked-but-failed-child.rs index 079c97013abee..998360f08ba0d 100644 --- a/src/test/run-pass/wait-forked-but-failed-child.rs +++ b/src/test/run-pass/wait-forked-but-failed-child.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(libc, old_io)] diff --git a/src/test/run-pass/where-for-self.rs b/src/test/run-pass/where-for-self.rs index eb95b13d3fa5b..1d477b87446d4 100644 --- a/src/test/run-pass/where-for-self.rs +++ b/src/test/run-pass/where-for-self.rs @@ -11,7 +11,6 @@ // Test that we can quantify lifetimes outside a constraint (i.e., including // the self type) in a where clause. -// pretty-expanded FIXME #23616 static mut COUNT: u32 = 1; diff --git a/src/test/run-pass/while-label.rs b/src/test/run-pass/while-label.rs index 076ba8f428f06..8cbb845836f3e 100644 --- a/src/test/run-pass/while-label.rs +++ b/src/test/run-pass/while-label.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let mut i = 100; diff --git a/src/test/run-pass/while-let.rs b/src/test/run-pass/while-let.rs index b1e80c86ec72d..5a2ecdd45dbe5 100644 --- a/src/test/run-pass/while-let.rs +++ b/src/test/run-pass/while-let.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections)] diff --git a/src/test/run-pass/writealias.rs b/src/test/run-pass/writealias.rs index 10718e981ff59..7339fe47dc297 100644 --- a/src/test/run-pass/writealias.rs +++ b/src/test/run-pass/writealias.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::sync::Mutex; diff --git a/src/test/run-pass/xcrate-address-insignificant.rs b/src/test/run-pass/xcrate-address-insignificant.rs index ac8b15d7bf589..8794ecd061b47 100644 --- a/src/test/run-pass/xcrate-address-insignificant.rs +++ b/src/test/run-pass/xcrate-address-insignificant.rs @@ -10,7 +10,6 @@ // aux-build:xcrate_address_insignificant.rs -// pretty-expanded FIXME #23616 extern crate xcrate_address_insignificant as foo; diff --git a/src/test/run-pass/zero-size-type-destructors.rs b/src/test/run-pass/zero-size-type-destructors.rs index dea9edf0582bd..a80faeaea7ea7 100644 --- a/src/test/run-pass/zero-size-type-destructors.rs +++ b/src/test/run-pass/zero-size-type-destructors.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_no_drop_flag)] diff --git a/src/test/run-pass/zero_sized_subslice_match.rs b/src/test/run-pass/zero_sized_subslice_match.rs index b98f907774b97..697508ae48889 100644 --- a/src/test/run-pass/zero_sized_subslice_match.rs +++ b/src/test/run-pass/zero_sized_subslice_match.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] From a725426ec8464e17794b0e8d0a06d33ba6ea95f0 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 8 Apr 2015 18:01:46 -0700 Subject: [PATCH 45/62] Don't deoptimize llvm when --enable-debug libLTO fails to link here. --- configure | 1 - 1 file changed, 1 deletion(-) diff --git a/configure b/configure index b23cfaf976f0e..97c998a5cda3c 100755 --- a/configure +++ b/configure @@ -631,7 +631,6 @@ if [ -n "$CFG_ENABLE_DEBUG" ]; then msg "debug mode enabled, setting performance options" CFG_DISABLE_OPTIMIZE=1 CFG_DISABLE_OPTIMIZE_CXX=1 - CFG_DISABLE_OPTIMIZE_LLVM=1 CFG_ENABLE_LLVM_ASSERTIONS=1 CFG_ENABLE_DEBUG_ASSERTIONS=1 CFG_ENABLE_DEBUG_JEMALLOC=1 From 0a380a9318cb450fc54153c1327a35cf02fab8e6 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Tue, 7 Apr 2015 16:01:21 -0700 Subject: [PATCH 46/62] Implement io::Seek for io::BufReader where R: io::Seek Seeking the `BufReader` discards the internal buffer (and adjusts the offset appropriately when seeking with `SeekFrom::Current(_)`). --- src/libstd/io/buffered.rs | 111 +++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 2 deletions(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 6fe35614a85b6..6d514418e1631 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -18,7 +18,7 @@ use io::prelude::*; use cmp; use error; use fmt; -use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind}; +use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom}; use ptr; use iter; @@ -120,6 +120,52 @@ impl fmt::Debug for BufReader where R: fmt::Debug { } } +#[unstable(feature = "buf_seek", reason = "recently added")] +impl Seek for BufReader { + /// Seek to an offset, in bytes, in the underlying reader. + /// + /// The position used for seeking with `SeekFrom::Current(_)` is the + /// position the underlying reader would be at if the `BufReader` had no + /// internal buffer. + /// + /// Seeking always discards the internal buffer, even if the seek position + /// would otherwise fall within it. This guarantees that calling + /// `.unwrap()` immediately after a seek yields the underlying reader at + /// the same position. + /// + /// See `std::io::Seek` for more details. + /// + /// Note: In the edge case where you're seeking with `SeekFrom::Current(n)` + /// where `n` minus the internal buffer length underflows an `i64`, two + /// seeks will be performed instead of one. If the second seek returns + /// `Err`, the underlying reader will be left at the same position it would + /// have if you seeked to `SeekFrom::Current(0)`. + fn seek(&mut self, pos: SeekFrom) -> io::Result { + let result: u64; + if let SeekFrom::Current(n) = pos { + let remainder = (self.cap - self.pos) as i64; + // it should be safe to assume that remainder fits within an i64 as the alternative + // means we managed to allocate 8 ebibytes and that's absurd. + // But it's not out of the realm of possibility for some weird underlying reader to + // support seeking by i64::min_value() so we need to handle underflow when subtracting + // remainder. + if let Some(offset) = n.checked_sub(remainder) { + result = try!(self.inner.seek(SeekFrom::Current(offset))); + } else { + // seek backwards by our remainder, and then by the offset + try!(self.inner.seek(SeekFrom::Current(-remainder))); + self.pos = self.cap; // empty the buffer + result = try!(self.inner.seek(SeekFrom::Current(n))); + } + } else { + // Seeking with Start/End doesn't care about our buffer length. + result = try!(self.inner.seek(pos)); + } + self.pos = self.cap; // empty the buffer + Ok(result) + } +} + /// Wraps a Writer and buffers output to it /// /// It can be excessively inefficient to work directly with a `Write`. For @@ -478,7 +524,7 @@ impl fmt::Debug for BufStream where S: fmt::Debug { mod tests { use prelude::v1::*; use io::prelude::*; - use io::{self, BufReader, BufWriter, BufStream, Cursor, LineWriter}; + use io::{self, BufReader, BufWriter, BufStream, Cursor, LineWriter, SeekFrom}; use test; /// A dummy reader intended at testing short-reads propagation. @@ -533,6 +579,67 @@ mod tests { assert_eq!(reader.read(&mut buf).unwrap(), 0); } + #[test] + fn test_buffered_reader_seek() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); + + assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3)); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4)); + assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..])); + reader.consume(1); + assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3)); + } + + #[test] + fn test_buffered_reader_seek_underflow() { + // gimmick reader that yields its position modulo 256 for each byte + struct PositionReader { + pos: u64 + } + impl Read for PositionReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let len = buf.len(); + for x in buf { + *x = self.pos as u8; + self.pos = self.pos.wrapping_add(1); + } + Ok(len) + } + } + impl Seek for PositionReader { + fn seek(&mut self, pos: SeekFrom) -> io::Result { + match pos { + SeekFrom::Start(n) => { + self.pos = n; + } + SeekFrom::Current(n) => { + self.pos = self.pos.wrapping_add(n as u64); + } + SeekFrom::End(n) => { + self.pos = u64::max_value().wrapping_add(n as u64); + } + } + Ok(self.pos) + } + } + + let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 }); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..])); + assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::max_value()-5)); + assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); + // the following seek will require two underlying seeks + let expected = 9223372036854775802; + assert_eq!(reader.seek(SeekFrom::Current(i64::min_value())).ok(), Some(expected)); + assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); + // seeking to 0 should empty the buffer. + assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected)); + assert_eq!(reader.get_ref().pos, expected); + } + #[test] fn test_buffered_writer() { let inner = Vec::new(); From 16052053ac2668b5540a55383924ce36e7018933 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Tue, 7 Apr 2015 17:29:33 -0700 Subject: [PATCH 47/62] Implement io::Seek for io::BufWriter where W: io::Seek Seeking the `BufWriter` writes out its internal buffer before seeking. --- src/libstd/io/buffered.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 6d514418e1631..bd44a9547b496 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -284,6 +284,16 @@ impl fmt::Debug for BufWriter where W: fmt::Debug { } } +#[unstable(feature = "buf_seek", reason = "recently added")] +impl Seek for BufWriter { + /// Seek to the offset, in bytes, in the underlying writer. + /// + /// Seeking always writes out the internal buffer before seeking. + fn seek(&mut self, pos: SeekFrom) -> io::Result { + self.flush_buf().and_then(|_| self.get_mut().seek(pos)) + } +} + #[unsafe_destructor] impl Drop for BufWriter { fn drop(&mut self) { @@ -683,6 +693,18 @@ mod tests { assert_eq!(w, [0, 1]); } + #[test] + fn test_buffered_writer_seek() { + let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new())); + w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap(); + w.write_all(&[6, 7]).unwrap(); + assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8)); + assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]); + assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2)); + w.write_all(&[8, 9]).unwrap(); + assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]); + } + // This is just here to make sure that we don't infinite loop in the // newtype struct autoderef weirdness #[test] From 613cf9a2a12a29a2454bc9d5bb83243cf0868955 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 9 Apr 2015 18:25:48 +1200 Subject: [PATCH 48/62] Debug impls for a few things in syntax::codemap --- src/libsyntax/codemap.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index b563a5e7d6e84..56af43474a615 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -26,6 +26,8 @@ use std::num::ToPrimitive; use std::ops::{Add, Sub}; use std::rc::Rc; +use std::fmt; + use libc::c_uint; use serialize::{Encodable, Decodable, Encoder, Decoder}; @@ -199,6 +201,7 @@ pub fn original_sp(cm: &CodeMap, sp: Span, enclosing_sp: Span) -> Span { // /// A source code location used for error reporting +#[derive(Debug)] pub struct Loc { /// Information about the original source pub file: Rc, @@ -211,6 +214,7 @@ pub struct Loc { /// A source code location used as the result of lookup_char_pos_adj // Actually, *none* of the clients use the filename *or* file field; // perhaps they should just be removed. +#[derive(Debug)] pub struct LocWithOpt { pub filename: FileName, pub line: usize, @@ -219,7 +223,9 @@ pub struct LocWithOpt { } // used to be structural records. Better names, anyone? +#[derive(Debug)] pub struct FileMapAndLine { pub fm: Rc, pub line: usize } +#[derive(Debug)] pub struct FileMapAndBytePos { pub fm: Rc, pub pos: BytePos } @@ -449,6 +455,12 @@ impl Decodable for FileMap { } } +impl fmt::Debug for FileMap { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "FileMap({})", self.name) + } +} + impl FileMap { /// EFFECT: register a start-of-line offset in the /// table of line-beginnings. From 341870a2d1a3b51d3dc7e36c3a7bc5a704a9bd19 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 9 Apr 2015 20:35:27 +1200 Subject: [PATCH 49/62] Fix the span for `for` expressions --- src/libsyntax/parse/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 272bb5f650676..3cc16006b1b9c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2880,7 +2880,7 @@ impl<'a> Parser<'a> { try!(self.expect_keyword(keywords::In)); let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); let loop_block = try!(self.parse_block()); - let hi = self.span.hi; + let hi = self.last_span.hi; Ok(self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))) } From e3f324cd9d7b27eda6133c407a4751a8b0217631 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Wed, 8 Apr 2015 17:01:03 -0700 Subject: [PATCH 50/62] Improve bounds in Iterator API This commit changes `Iterator`'s API by: * Generalizing bounds from `Iterator` to `IntoIterator` whenever possible, matching the semantics and ergonomics of `for` loops. * Tightens up a few method-level bounds so that you get an error earlier. For example, `rev` did not require `DoubleEndedIterator` even though the result is only an `Iterator` when the original iterator was double-ended. Closes #23587 The bound-tightening is technically a: [breaking-change] but no code should break in practice. --- src/libcore/iter.rs | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index ffe49a25a0d2f..8cbdda758697b 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -171,10 +171,10 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn chain(self, other: U) -> Chain where - Self: Sized, U: Iterator, + fn chain(self, other: U) -> Chain where + Self: Sized, U: IntoIterator, { - Chain{a: self, b: other, flag: false} + Chain{a: self, b: other.into_iter(), flag: false} } /// Creates an iterator that iterates over both this and the specified @@ -207,8 +207,10 @@ pub trait Iterator { /// both produce the same output. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn zip(self, other: U) -> Zip where Self: Sized { - Zip{a: self, b: other} + fn zip(self, other: U) -> Zip where + Self: Sized, U: IntoIterator + { + Zip{a: self, b: other.into_iter()} } /// Creates a new iterator that will apply the specified function to each @@ -443,7 +445,7 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn flat_map(self, f: F) -> FlatMap - where Self: Sized, U: Iterator, F: FnMut(Self::Item) -> U, + where Self: Sized, U: IntoIterator, F: FnMut(Self::Item) -> U, { FlatMap{iter: self, f: f, frontiter: None, backiter: None } } @@ -933,7 +935,7 @@ pub trait Iterator { /// `std::usize::MAX` elements of the original iterator. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn rev(self) -> Rev where Self: Sized { + fn rev(self) -> Rev where Self: Sized + DoubleEndedIterator { Rev{iter: self} } @@ -2093,15 +2095,15 @@ impl Iterator for Scan where #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] -pub struct FlatMap { +pub struct FlatMap { iter: I, f: F, - frontiter: Option, - backiter: Option, + frontiter: Option, + backiter: Option, } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for FlatMap +impl Iterator for FlatMap where F: FnMut(I::Item) -> U, { type Item = U::Item; @@ -2110,13 +2112,13 @@ impl Iterator for FlatMap fn next(&mut self) -> Option { loop { if let Some(ref mut inner) = self.frontiter { - for x in inner.by_ref() { + if let Some(x) = inner.by_ref().next() { return Some(x) } } match self.iter.next().map(|x| (self.f)(x)) { None => return self.backiter.as_mut().and_then(|it| it.next()), - next => self.frontiter = next, + next => self.frontiter = next.map(IntoIterator::into_iter), } } } @@ -2134,22 +2136,22 @@ impl Iterator for FlatMap } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator - for FlatMap - where F: FnMut(I::Item) -> U +impl DoubleEndedIterator for FlatMap where + F: FnMut(I::Item) -> U, + U: IntoIterator, + U::IntoIter: DoubleEndedIterator { #[inline] fn next_back(&mut self) -> Option { loop { if let Some(ref mut inner) = self.backiter { - match inner.next_back() { - None => (), - y => return y + if let Some(y) = inner.next_back() { + return Some(y) } } match self.iter.next_back().map(|x| (self.f)(x)) { None => return self.frontiter.as_mut().and_then(|it| it.next_back()), - next => self.backiter = next, + next => self.backiter = next.map(IntoIterator::into_iter), } } } From 549bd55eed605604da91b0ec5b61521a82bb76ec Mon Sep 17 00:00:00 2001 From: Thiago Carvalho Date: Thu, 9 Apr 2015 18:07:33 +0200 Subject: [PATCH 51/62] resurrect research paper list #24004 --- src/doc/trpl/SUMMARY.md | 1 + src/doc/trpl/academic-research.md | 46 +++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 src/doc/trpl/academic-research.md diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index d894e1c47253b..8853001191ca9 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -67,3 +67,4 @@ * [Benchmark Tests](benchmark-tests.md) * [Box Syntax and Patterns](box-syntax-and-patterns.md) * [Glossary](glossary.md) +* [Academic Research](academic-research.md) diff --git a/src/doc/trpl/academic-research.md b/src/doc/trpl/academic-research.md new file mode 100644 index 0000000000000..f4f066fb3dfe3 --- /dev/null +++ b/src/doc/trpl/academic-research.md @@ -0,0 +1,46 @@ +% Academic Research + +An incomplete list of papers that have had some influence in Rust. + +Recommended for inspiration and a better understanding of Rust's background. + +### Type system + +* [Region based memory management in Cyclone](http://209.68.42.137/ucsd-pages/Courses/cse227.w03/handouts/cyclone-regions.pdf) +* [Safe manual memory management in Cyclone](http://www.cs.umd.edu/projects/PL/cyclone/scp.pdf) +* [Typeclasses: making ad-hoc polymorphism less ad hoc](http://www.ps.uni-sb.de/courses/typen-ws99/class.ps.gz) +* [Macros that work together](https://www.cs.utah.edu/plt/publications/jfp12-draft-fcdf.pdf) +* [Traits: composable units of behavior](http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf) +* [Alias burying](http://www.cs.uwm.edu/faculty/boyland/papers/unique-preprint.ps) - We tried something similar and abandoned it. +* [External uniqueness is unique enough](http://www.computingscience.nl/research/techreps/repo/CS-2002/2002-048.pdf) +* [Uniqueness and Reference Immutability for Safe Parallelism](https://research.microsoft.com/pubs/170528/msr-tr-2012-79.pdf) +* [Region Based Memory Management](http://www.cs.ucla.edu/~palsberg/tba/papers/tofte-talpin-iandc97.pdf) + +### Concurrency + +* [Singularity: rethinking the software stack](https://research.microsoft.com/pubs/69431/osr2007_rethinkingsoftwarestack.pdf) +* [Language support for fast and reliable message passing in singularity OS](https://research.microsoft.com/pubs/67482/singsharp.pdf) +* [Scheduling multithreaded computations by work stealing](http://supertech.csail.mit.edu/papers/steal.pdf) +* [Thread scheduling for multiprogramming multiprocessors](http://www.eecis.udel.edu/%7Ecavazos/cisc879-spring2008/papers/arora98thread.pdf) +* [The data locality of work stealing](http://www.aladdin.cs.cmu.edu/papers/pdfs/y2000/locality_spaa00.pdf) +* [Dynamic circular work stealing deque](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.170.1097&rep=rep1&type=pdf) - The Chase/Lev deque +* [Work-first and help-first scheduling policies for async-finish task parallelism](http://www.cs.rice.edu/%7Eyguo/pubs/PID824943.pdf) - More general than fully-strict work stealing +* [A Java fork/join calamity](http://www.coopsoft.com/ar/CalamityArticle.html) - critique of Java's fork/join library, particularly its application of work stealing to non-strict computation +* [Scheduling techniques for concurrent systems](http://www.ece.rutgers.edu/%7Eparashar/Classes/ece572-papers/05/ps-ousterhout.pdf) +* [Contention aware scheduling](http://www.blagodurov.net/files/a8-blagodurov.pdf) +* [Balanced work stealing for time-sharing multicores](http://www.cse.ohio-state.edu/hpcs/WWW/HTML/publications/papers/TR-12-1.pdf) +* [Three layer cake](http://www.upcrc.illinois.edu/workshops/paraplop10/papers/paraplop10_submission_8.pdf) +* [Non-blocking steal-half work queues](http://www.cs.bgu.ac.il/%7Ehendlerd/papers/p280-hendler.pdf) +* [Reagents: expressing and composing fine-grained concurrency](http://www.mpi-sws.org/~turon/reagents.pdf) +* [Algorithms for scalable synchronization of shared-memory multiprocessors](https://www.cs.rochester.edu/u/scott/papers/1991_TOCS_synch.pdf) + +### Others + +* [Crash-only software](https://www.usenix.org/legacy/events/hotos03/tech/full_papers/candea/candea.pdf) +* [Composing High-Performance Memory Allocators](http://people.cs.umass.edu/~emery/pubs/berger-pldi2001.pdf) +* [Reconsidering Custom Memory Allocation](http://people.cs.umass.edu/~emery/pubs/berger-oopsla2002.pdf) + +### Papers *about* Rust + +* [GPU programming in Rust](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf) +* [Parallel closures: a new twist on an old idea](https://www.usenix.org/conference/hotpar12/parallel-closures-new-twist-old-idea) - not exactly about rust, but by nmatsakis From c3aa05752c68adaf851c0d9d13bb71d1f116da86 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 9 Apr 2015 09:29:40 -0700 Subject: [PATCH 52/62] Add regression test for #19097 Closes #19097 --- src/test/run-pass/issue-19097.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/test/run-pass/issue-19097.rs diff --git a/src/test/run-pass/issue-19097.rs b/src/test/run-pass/issue-19097.rs new file mode 100644 index 0000000000000..ca4b72f9e5bd0 --- /dev/null +++ b/src/test/run-pass/issue-19097.rs @@ -0,0 +1,22 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// regression test for #19097 + +struct Foo(T); + +impl<'a, T> Foo<&'a T> { + fn foo(&self) {} +} +impl<'a, T> Foo<&'a mut T> { + fn foo(&self) {} +} + +fn main() {} From 746725a582f3773456fec546a5b18ccb6a63c5da Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 7 Apr 2015 06:10:53 -0400 Subject: [PATCH 53/62] Add librustc_data_structures crate --- mk/crates.mk | 11 ++++++---- src/librustc/lib.rs | 1 + src/librustc_data_structures/lib.rs | 33 +++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 src/librustc_data_structures/lib.rs diff --git a/mk/crates.mk b/mk/crates.mk index f594a6a19f158..27940df8f5e3f 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -54,7 +54,8 @@ TARGET_CRATES := libc std flate arena term \ log graphviz core rbml alloc \ unicode rustc_bitflags RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \ - rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint + rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ + rustc_data_structures HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros CRATES := $(TARGET_CRATES) $(HOST_CRATES) TOOLS := compiletest rustdoc rustc rustbook @@ -80,9 +81,10 @@ DEPS_rustc_resolve := rustc log syntax DEPS_rustc_privacy := rustc log syntax DEPS_rustc_lint := rustc log syntax DEPS_rustc := syntax flate arena serialize getopts rbml \ - log graphviz rustc_llvm rustc_back + log graphviz rustc_llvm rustc_back rustc_data_structures DEPS_rustc_llvm := native:rustllvm libc std DEPS_rustc_back := std syntax rustc_llvm flate log libc +DEPS_rustc_data_structures := std log serialize DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \ test rustc_lint DEPS_rustc_bitflags := core @@ -141,16 +143,17 @@ DOC_CRATES := $(filter-out rustc, \ $(filter-out rustc_trans, \ $(filter-out rustc_typeck, \ $(filter-out rustc_borrowck, \ + $(filter-out rustc_data_structures, \ $(filter-out rustc_resolve, \ $(filter-out rustc_driver, \ $(filter-out rustc_privacy, \ $(filter-out rustc_lint, \ $(filter-out log, \ $(filter-out getopts, \ - $(filter-out syntax, $(CRATES)))))))))))) + $(filter-out syntax, $(CRATES))))))))))))) #endif #endif -COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_resolve \ +COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_data_structures rustc_resolve \ rustc_typeck rustc_driver syntax rustc_privacy \ rustc_lint diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a4bb17bc35476..4f7bb3d528a26 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -54,6 +54,7 @@ extern crate graphviz; extern crate libc; extern crate rustc_llvm; extern crate rustc_back; +extern crate rustc_data_structures; extern crate serialize; extern crate rbml; extern crate collections; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs new file mode 100644 index 0000000000000..abac991e5ce38 --- /dev/null +++ b/src/librustc_data_structures/lib.rs @@ -0,0 +1,33 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Various data structures used by the Rust compiler. The intention +//! is that code in here should be not be *specific* to rustc, so that +//! it can be easily unit tested and so forth. +//! +//! # Note +//! +//! This API is completely unstable and subject to change. + +// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364) +#![cfg_attr(stage0, feature(custom_attribute))] +#![crate_name = "rustc_data_structures"] +#![unstable(feature = "rustc_private")] +#![crate_type = "dylib"] +#![crate_type = "rlib"] +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://doc.rust-lang.org/nightly/")] + +#![feature(rustc_private)] +#![feature(test)] + +#[macro_use] extern crate log; +extern crate serialize as rustc_serialize; // used by deriving From af273d274933064b784f4b429ed63333caf3d46d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 7 Apr 2015 06:11:49 -0400 Subject: [PATCH 54/62] Use the newer snapshot_vec, which has a simplified delegate interface since in practice no delegates had any state. --- src/librustc/lib.rs | 1 - src/librustc/middle/infer/type_variable.rs | 8 ++--- src/librustc/middle/infer/unify.rs | 6 ++-- src/librustc_data_structures/lib.rs | 2 ++ .../snapshot_vec.rs | 31 ++++++++++++++++--- 5 files changed, 34 insertions(+), 14 deletions(-) rename src/{librustc/util => librustc_data_structures}/snapshot_vec.rs (87%) diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 4f7bb3d528a26..6837483a4220e 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -142,7 +142,6 @@ pub mod util { pub mod common; pub mod ppaux; pub mod nodemap; - pub mod snapshot_vec; pub mod lev_distance; } diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs index 03612a6c1ae5b..b3e3e016d85c2 100644 --- a/src/librustc/middle/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs @@ -17,7 +17,7 @@ use std::cmp::min; use std::marker::PhantomData; use std::mem; use std::u32; -use util::snapshot_vec as sv; +use rustc_data_structures::snapshot_vec as sv; pub struct TypeVariableTable<'tcx> { values: sv::SnapshotVec>, @@ -65,7 +65,7 @@ impl RelationDir { impl<'tcx> TypeVariableTable<'tcx> { pub fn new() -> TypeVariableTable<'tcx> { - TypeVariableTable { values: sv::SnapshotVec::new(Delegate(PhantomData)) } + TypeVariableTable { values: sv::SnapshotVec::new() } } fn relations<'a>(&'a mut self, a: ty::TyVid) -> &'a mut Vec { @@ -201,9 +201,7 @@ impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { type Value = TypeVariableData<'tcx>; type Undo = UndoEntry; - fn reverse(&mut self, - values: &mut Vec>, - action: UndoEntry) { + fn reverse(values: &mut Vec>, action: UndoEntry) { match action { SpecifyVar(vid, relations) => { values[vid.index as usize].value = Bounded(relations); diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs index 4bbced1d75caf..5aec422713695 100644 --- a/src/librustc/middle/infer/unify.rs +++ b/src/librustc/middle/infer/unify.rs @@ -17,7 +17,7 @@ use middle::ty::{self, Ty}; use std::fmt::Debug; use std::marker::PhantomData; use syntax::ast; -use util::snapshot_vec as sv; +use rustc_data_structures::snapshot_vec as sv; /// This trait is implemented by any type that can serve as a type /// variable. We call such variables *unification keys*. For example, @@ -95,7 +95,7 @@ pub struct Delegate(PhantomData); impl UnificationTable { pub fn new() -> UnificationTable { UnificationTable { - values: sv::SnapshotVec::new(Delegate(PhantomData)), + values: sv::SnapshotVec::new(), } } @@ -213,7 +213,7 @@ impl sv::SnapshotVecDelegate for Delegate { type Value = VarValue; type Undo = (); - fn reverse(&mut self, _: &mut Vec>, _: ()) { + fn reverse(_: &mut Vec>, _: ()) { panic!("Nothing to reverse"); } } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index abac991e5ce38..5f2f430df5039 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -31,3 +31,5 @@ #[macro_use] extern crate log; extern crate serialize as rustc_serialize; // used by deriving + +pub mod snapshot_vec; diff --git a/src/librustc/util/snapshot_vec.rs b/src/librustc_data_structures/snapshot_vec.rs similarity index 87% rename from src/librustc/util/snapshot_vec.rs rename to src/librustc_data_structures/snapshot_vec.rs index d2e0b3aec2f40..5ab740f3629aa 100644 --- a/src/librustc/util/snapshot_vec.rs +++ b/src/librustc_data_structures/snapshot_vec.rs @@ -21,6 +21,7 @@ use self::UndoLog::*; use std::mem; +use std::ops; pub enum UndoLog { /// Indicates where a snapshot started. @@ -42,7 +43,6 @@ pub enum UndoLog { pub struct SnapshotVec { values: Vec, undo_log: Vec>, - delegate: D } // Snapshots are tokens that should be created/consumed linearly. @@ -55,15 +55,14 @@ pub trait SnapshotVecDelegate { type Value; type Undo; - fn reverse(&mut self, values: &mut Vec, action: Self::Undo); + fn reverse(values: &mut Vec, action: Self::Undo); } impl SnapshotVec { - pub fn new(delegate: D) -> SnapshotVec { + pub fn new() -> SnapshotVec { SnapshotVec { values: Vec::new(), undo_log: Vec::new(), - delegate: delegate } } @@ -77,6 +76,10 @@ impl SnapshotVec { } } + pub fn len(&self) -> usize { + self.values.len() + } + pub fn push(&mut self, elem: D::Value) -> usize { let len = self.values.len(); self.values.push(elem); @@ -159,7 +162,7 @@ impl SnapshotVec { } Other(u) => { - self.delegate.reverse(&mut self.values, u); + D::reverse(&mut self.values, u); } } } @@ -184,3 +187,21 @@ impl SnapshotVec { } } } + +impl ops::Deref for SnapshotVec { + type Target = [D::Value]; + fn deref(&self) -> &[D::Value] { &*self.values } +} + +impl ops::DerefMut for SnapshotVec { + fn deref_mut(&mut self) -> &mut [D::Value] { &mut *self.values } +} + +impl ops::Index for SnapshotVec { + type Output = D::Value; + fn index(&self, index: usize) -> &D::Value { self.get(index) } +} + +impl ops::IndexMut for SnapshotVec { + fn index_mut(&mut self, index: usize) -> &mut D::Value { self.get_mut(index) } +} From dbdb315b96fd73e7395ccb736528e52a0ee84616 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 7 Apr 2015 06:12:13 -0400 Subject: [PATCH 55/62] Port to using the newer graph, which offers iterators instead of the older `each` method, but is otherwise identical. --- src/librustc/lib.rs | 1 - src/librustc/middle/cfg/construct.rs | 2 +- src/librustc/middle/cfg/mod.rs | 5 +- src/librustc/middle/dataflow.rs | 5 +- .../middle/infer/region_inference/mod.rs | 30 +- src/librustc_data_structures/bitvec.rs | 32 ++ .../graph/mod.rs} | 353 +++++++----------- src/librustc_data_structures/graph/test.rs | 129 +++++++ src/librustc_data_structures/lib.rs | 2 + src/librustc_lint/builtin.rs | 5 +- 10 files changed, 320 insertions(+), 244 deletions(-) create mode 100644 src/librustc_data_structures/bitvec.rs rename src/{librustc/middle/graph.rs => librustc_data_structures/graph/mod.rs} (50%) create mode 100644 src/librustc_data_structures/graph/test.rs diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 6837483a4220e..ab5c4e7696601 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -104,7 +104,6 @@ pub mod middle { pub mod entry; pub mod expr_use_visitor; pub mod fast_reject; - pub mod graph; pub mod intrinsicck; pub mod infer; pub mod lang_items; diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index cbc2ef1535ea6..359a1a486c9da 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc_data_structures::graph; use middle::cfg::*; use middle::def; -use middle::graph; use middle::pat_util; use middle::region::CodeExtent; use middle::ty; diff --git a/src/librustc/middle/cfg/mod.rs b/src/librustc/middle/cfg/mod.rs index ad4fdcd7b834e..3ca221c9630be 100644 --- a/src/librustc/middle/cfg/mod.rs +++ b/src/librustc/middle/cfg/mod.rs @@ -11,7 +11,7 @@ //! Module that constructs a control-flow graph representing an item. //! Uses `Graph` as the underlying representation. -use middle::graph; +use rustc_data_structures::graph; use middle::ty; use syntax::ast; @@ -24,7 +24,7 @@ pub struct CFG { pub exit: CFGIndex, } -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum CFGNodeData { AST(ast::NodeId), Entry, @@ -43,6 +43,7 @@ impl CFGNodeData { } } +#[derive(Debug)] pub struct CFGEdgeData { pub exiting_scopes: Vec } diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index b20e4c3f563ca..27da7c89b2c68 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -530,10 +530,9 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> { pred_bits: &[usize], cfg: &cfg::CFG, cfgidx: CFGIndex) { - cfg.graph.each_outgoing_edge(cfgidx, |_e_idx, edge| { + for (_, edge) in cfg.graph.outgoing_edges(cfgidx) { self.propagate_bits_into_entry_set_for(pred_bits, edge); - true - }); + } } fn propagate_bits_into_entry_set_for(&mut self, diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index d41fdc5f09acd..9194212d964b5 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -20,14 +20,13 @@ use self::Classification::*; use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}; +use rustc_data_structures::graph::{self, Direction, NodeIndex}; use middle::region; use middle::ty::{self, Ty}; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound}; use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; use middle::ty_relate::RelateResult; -use middle::graph; -use middle::graph::{Direction, NodeIndex}; use util::common::indenter; use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux::{Repr, UserString}; @@ -1325,10 +1324,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { let num_vars = self.num_vars(); let constraints = self.constraints.borrow(); - let num_edges = constraints.len(); - let mut graph = graph::Graph::with_capacity(num_vars as usize + 1, - num_edges); + let mut graph = graph::Graph::new(); for _ in 0..num_vars { graph.add_node(()); @@ -1370,10 +1367,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // not contained by an upper-bound. let (mut lower_bounds, lower_dup) = self.collect_concrete_regions(graph, var_data, node_idx, - graph::Incoming, dup_vec); + graph::INCOMING, dup_vec); let (mut upper_bounds, upper_dup) = self.collect_concrete_regions(graph, var_data, node_idx, - graph::Outgoing, dup_vec); + graph::OUTGOING, dup_vec); if lower_dup || upper_dup { return; @@ -1433,7 +1430,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // that have no intersection. let (upper_bounds, dup_found) = self.collect_concrete_regions(graph, var_data, node_idx, - graph::Outgoing, dup_vec); + graph::OUTGOING, dup_vec); if dup_found { return; @@ -1508,8 +1505,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // figure out the direction from which this node takes its // values, and search for concrete regions etc in that direction let dir = match classification { - Expanding => graph::Incoming, - Contracting => graph::Outgoing, + Expanding => graph::INCOMING, + Contracting => graph::OUTGOING, }; process_edges(self, &mut state, graph, node_idx, dir); @@ -1519,14 +1516,14 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { return (result, dup_found); fn process_edges<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>, - state: &mut WalkState<'tcx>, - graph: &RegionGraph, - source_vid: RegionVid, - dir: Direction) { + state: &mut WalkState<'tcx>, + graph: &RegionGraph, + source_vid: RegionVid, + dir: Direction) { debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir); let source_node_index = NodeIndex(source_vid.index as usize); - graph.each_adjacent_edge(source_node_index, dir, |_, edge| { + for (_, edge) in graph.adjacent_edges(source_node_index, dir) { match edge.data { ConstrainVarSubVar(from_vid, to_vid) => { let opp_vid = @@ -1544,8 +1541,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { }); } } - true - }); + } } } diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs new file mode 100644 index 0000000000000..f5924ef5a3f63 --- /dev/null +++ b/src/librustc_data_structures/bitvec.rs @@ -0,0 +1,32 @@ +use std::iter; + +/// A very simple BitVector type. +pub struct BitVector { + data: Vec +} + +impl BitVector { + pub fn new(num_bits: usize) -> BitVector { + let num_words = (num_bits + 63) / 64; + BitVector { data: iter::repeat(0).take(num_words).collect() } + } + + fn word_mask(&self, bit: usize) -> (usize, u64) { + let word = bit / 64; + let mask = 1 << (bit % 64); + (word, mask) + } + + pub fn contains(&self, bit: usize) -> bool { + let (word, mask) = self.word_mask(bit); + (self.data[word] & mask) != 0 + } + + pub fn insert(&mut self, bit: usize) -> bool { + let (word, mask) = self.word_mask(bit); + let data = &mut self.data[word]; + let value = *data; + *data = value | mask; + (value | mask) != value + } +} diff --git a/src/librustc/middle/graph.rs b/src/librustc_data_structures/graph/mod.rs similarity index 50% rename from src/librustc/middle/graph.rs rename to src/librustc_data_structures/graph/mod.rs index a9ac61b49eca8..5741544fe5419 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -30,15 +30,17 @@ //! the field `next_edge`). Each of those fields is an array that should //! be indexed by the direction (see the type `Direction`). -#![allow(dead_code)] // still WIP - +use bitvec::BitVector; use std::fmt::{Formatter, Error, Debug}; use std::usize; -use std::collections::BitSet; +use snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; + +#[cfg(test)] +mod test; pub struct Graph { - nodes: Vec> , - edges: Vec> , + nodes: SnapshotVec> , + edges: SnapshotVec> , } pub struct Node { @@ -53,6 +55,20 @@ pub struct Edge { pub data: E, } +impl SnapshotVecDelegate for Node { + type Value = Node; + type Undo = (); + + fn reverse(_: &mut Vec>, _: ()) {} +} + +impl SnapshotVecDelegate for Edge { + type Value = Edge; + type Undo = (); + + fn reverse(_: &mut Vec>, _: ()) {} +} + impl Debug for Edge { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { write!(f, "Edge {{ next_edge: [{:?}, {:?}], source: {:?}, target: {:?}, data: {:?} }}", @@ -61,49 +77,37 @@ impl Debug for Edge { } } -#[derive(Clone, Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub struct NodeIndex(pub usize); -#[allow(non_upper_case_globals)] -pub const InvalidNodeIndex: NodeIndex = NodeIndex(usize::MAX); #[derive(Copy, Clone, PartialEq, Debug)] pub struct EdgeIndex(pub usize); -#[allow(non_upper_case_globals)] -pub const InvalidEdgeIndex: EdgeIndex = EdgeIndex(usize::MAX); + +pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX); // Use a private field here to guarantee no more instances are created: #[derive(Copy, Clone, Debug)] pub struct Direction { repr: usize } -#[allow(non_upper_case_globals)] -pub const Outgoing: Direction = Direction { repr: 0 }; -#[allow(non_upper_case_globals)] -pub const Incoming: Direction = Direction { repr: 1 }; + +pub const OUTGOING: Direction = Direction { repr: 0 }; + +pub const INCOMING: Direction = Direction { repr: 1 }; impl NodeIndex { - fn get(&self) -> usize { let NodeIndex(v) = *self; v } /// Returns unique id (unique with respect to the graph holding associated node). - pub fn node_id(&self) -> usize { self.get() } + pub fn node_id(&self) -> usize { self.0 } } impl EdgeIndex { - fn get(&self) -> usize { let EdgeIndex(v) = *self; v } /// Returns unique id (unique with respect to the graph holding associated edge). - pub fn edge_id(&self) -> usize { self.get() } + pub fn edge_id(&self) -> usize { self.0 } } -impl Graph { +impl Graph { pub fn new() -> Graph { Graph { - nodes: Vec::new(), - edges: Vec::new(), - } - } - - pub fn with_capacity(num_nodes: usize, - num_edges: usize) -> Graph { - Graph { - nodes: Vec::with_capacity(num_nodes), - edges: Vec::with_capacity(num_edges), + nodes: SnapshotVec::new(), + edges: SnapshotVec::new(), } } @@ -130,22 +134,22 @@ impl Graph { pub fn add_node(&mut self, data: N) -> NodeIndex { let idx = self.next_node_index(); self.nodes.push(Node { - first_edge: [InvalidEdgeIndex, InvalidEdgeIndex], + first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], data: data }); idx } pub fn mut_node_data<'a>(&'a mut self, idx: NodeIndex) -> &'a mut N { - &mut self.nodes[idx.get()].data + &mut self.nodes[idx.0].data } pub fn node_data<'a>(&'a self, idx: NodeIndex) -> &'a N { - &self.nodes[idx.get()].data + &self.nodes[idx.0].data } pub fn node<'a>(&'a self, idx: NodeIndex) -> &'a Node { - &self.nodes[idx.get()] + &self.nodes[idx.0] } /////////////////////////////////////////////////////////////////////////// @@ -159,13 +163,15 @@ impl Graph { source: NodeIndex, target: NodeIndex, data: E) -> EdgeIndex { + debug!("graph: add_edge({:?}, {:?}, {:?})", source, target, data); + let idx = self.next_edge_index(); // read current first of the list of edges from each node - let source_first = self.nodes[source.get()] - .first_edge[Outgoing.repr]; - let target_first = self.nodes[target.get()] - .first_edge[Incoming.repr]; + let source_first = self.nodes[source.0] + .first_edge[OUTGOING.repr]; + let target_first = self.nodes[target.0] + .first_edge[INCOMING.repr]; // create the new edge, with the previous firsts from each node // as the next pointers @@ -177,22 +183,22 @@ impl Graph { }); // adjust the firsts for each node target be the next object. - self.nodes[source.get()].first_edge[Outgoing.repr] = idx; - self.nodes[target.get()].first_edge[Incoming.repr] = idx; + self.nodes[source.0].first_edge[OUTGOING.repr] = idx; + self.nodes[target.0].first_edge[INCOMING.repr] = idx; return idx; } pub fn mut_edge_data<'a>(&'a mut self, idx: EdgeIndex) -> &'a mut E { - &mut self.edges[idx.get()].data + &mut self.edges[idx.0].data } pub fn edge_data<'a>(&'a self, idx: EdgeIndex) -> &'a E { - &self.edges[idx.get()].data + &self.edges[idx.0].data } pub fn edge<'a>(&'a self, idx: EdgeIndex) -> &'a Edge { - &self.edges[idx.get()] + &self.edges[idx.0] } pub fn first_adjacent(&self, node: NodeIndex, dir: Direction) -> EdgeIndex { @@ -200,7 +206,7 @@ impl Graph { //! This is useful if you wish to modify the graph while walking //! the linked list of edges. - self.nodes[node.get()].first_edge[dir.repr] + self.nodes[node.0].first_edge[dir.repr] } pub fn next_adjacent(&self, edge: EdgeIndex, dir: Direction) -> EdgeIndex { @@ -208,7 +214,7 @@ impl Graph { //! This is useful if you wish to modify the graph while walking //! the linked list of edges. - self.edges[edge.get()].next_edge[dir.repr] + self.edges[edge.0].next_edge[dir.repr] } /////////////////////////////////////////////////////////////////////////// @@ -228,41 +234,25 @@ impl Graph { self.edges.iter().enumerate().all(|(i, edge)| f(EdgeIndex(i), edge)) } - pub fn each_outgoing_edge<'a, F>(&'a self, source: NodeIndex, f: F) -> bool where - F: FnMut(EdgeIndex, &'a Edge) -> bool, - { - //! Iterates over all outgoing edges from the node `from` + pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges { + self.adjacent_edges(source, OUTGOING) + } - self.each_adjacent_edge(source, Outgoing, f) + pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges { + self.adjacent_edges(source, INCOMING) } - pub fn each_incoming_edge<'a, F>(&'a self, target: NodeIndex, f: F) -> bool where - F: FnMut(EdgeIndex, &'a Edge) -> bool, - { - //! Iterates over all incoming edges to the node `target` + pub fn adjacent_edges(&self, source: NodeIndex, direction: Direction) -> AdjacentEdges { + let first_edge = self.node(source).first_edge[direction.repr]; + AdjacentEdges { graph: self, direction: direction, next: first_edge } + } - self.each_adjacent_edge(target, Incoming, f) + pub fn successor_nodes<'a>(&'a self, source: NodeIndex) -> AdjacentTargets { + self.outgoing_edges(source).targets() } - pub fn each_adjacent_edge<'a, F>(&'a self, - node: NodeIndex, - dir: Direction, - mut f: F) - -> bool where - F: FnMut(EdgeIndex, &'a Edge) -> bool, - { - //! Iterates over all edges adjacent to the node `node` - //! in the direction `dir` (either `Outgoing` or `Incoming) - - let mut edge_idx = self.first_adjacent(node, dir); - while edge_idx != InvalidEdgeIndex { - let edge = &self.edges[edge_idx.get()]; - if !f(edge_idx, edge) { - return false; - } - edge_idx = edge.next_edge[dir.repr]; - } - return true; + pub fn predecessor_nodes<'a>(&'a self, target: NodeIndex) -> AdjacentSources { + self.incoming_edges(target).sources() } /////////////////////////////////////////////////////////////////////////// @@ -292,18 +282,82 @@ impl Graph { DepthFirstTraversal { graph: self, stack: vec![start], - visited: BitSet::new() + visited: BitVector::new(self.nodes.len()), + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Iterators + +pub struct AdjacentEdges<'g,N,E> + where N:'g, E:'g +{ + graph: &'g Graph, + direction: Direction, + next: EdgeIndex, +} + +impl<'g,N,E> AdjacentEdges<'g,N,E> { + fn targets(self) -> AdjacentTargets<'g,N,E> { + AdjacentTargets { edges: self } + } + + fn sources(self) -> AdjacentSources<'g,N,E> { + AdjacentSources { edges: self } + } +} + +impl<'g, N:Debug, E:Debug> Iterator for AdjacentEdges<'g, N, E> { + type Item = (EdgeIndex, &'g Edge); + + fn next(&mut self) -> Option<(EdgeIndex, &'g Edge)> { + let edge_index = self.next; + if edge_index == INVALID_EDGE_INDEX { + return None; } + + let edge = self.graph.edge(edge_index); + self.next = edge.next_edge[self.direction.repr]; + Some((edge_index, edge)) + } +} + +pub struct AdjacentTargets<'g,N:'g,E:'g> + where N:'g, E:'g +{ + edges: AdjacentEdges<'g,N,E>, +} + +impl<'g, N:Debug, E:Debug> Iterator for AdjacentTargets<'g, N, E> { + type Item = NodeIndex; + + fn next(&mut self) -> Option { + self.edges.next().map(|(_, edge)| edge.target) + } +} + +pub struct AdjacentSources<'g,N:'g,E:'g> + where N:'g, E:'g +{ + edges: AdjacentEdges<'g,N,E>, +} + +impl<'g, N:Debug, E:Debug> Iterator for AdjacentSources<'g, N, E> { + type Item = NodeIndex; + + fn next(&mut self) -> Option { + self.edges.next().map(|(_, edge)| edge.source) } } pub struct DepthFirstTraversal<'g, N:'g, E:'g> { graph: &'g Graph, stack: Vec, - visited: BitSet + visited: BitVector } -impl<'g, N, E> Iterator for DepthFirstTraversal<'g, N, E> { +impl<'g, N:Debug, E:Debug> Iterator for DepthFirstTraversal<'g, N, E> { type Item = &'g N; fn next(&mut self) -> Option<&'g N> { @@ -311,12 +365,12 @@ impl<'g, N, E> Iterator for DepthFirstTraversal<'g, N, E> { if !self.visited.insert(idx.node_id()) { continue; } - self.graph.each_outgoing_edge(idx, |_, e| -> bool { - if !self.visited.contains(&e.target().node_id()) { - self.stack.push(e.target()); + + for (_, edge) in self.graph.outgoing_edges(idx) { + if !self.visited.contains(edge.target().node_id()) { + self.stack.push(edge.target()); } - true - }); + } return Some(self.graph.node_data(idx)); } @@ -329,7 +383,7 @@ pub fn each_edge_index(max_edge_index: EdgeIndex, mut f: F) where F: FnMut(EdgeIndex) -> bool, { let mut i = 0; - let n = max_edge_index.get(); + let n = max_edge_index.0; while i < n { if !f(EdgeIndex(i)) { return; @@ -347,138 +401,3 @@ impl Edge { self.target } } - -#[cfg(test)] -mod test { - use middle::graph::*; - use std::fmt::Debug; - - type TestNode = Node<&'static str>; - type TestEdge = Edge<&'static str>; - type TestGraph = Graph<&'static str, &'static str>; - - fn create_graph() -> TestGraph { - let mut graph = Graph::new(); - - // Create a simple graph - // - // A -+> B --> C - // | | ^ - // | v | - // F D --> E - - let a = graph.add_node("A"); - let b = graph.add_node("B"); - let c = graph.add_node("C"); - let d = graph.add_node("D"); - let e = graph.add_node("E"); - let f = graph.add_node("F"); - - graph.add_edge(a, b, "AB"); - graph.add_edge(b, c, "BC"); - graph.add_edge(b, d, "BD"); - graph.add_edge(d, e, "DE"); - graph.add_edge(e, c, "EC"); - graph.add_edge(f, b, "FB"); - - return graph; - } - - #[test] - fn each_node() { - let graph = create_graph(); - let expected = ["A", "B", "C", "D", "E", "F"]; - graph.each_node(|idx, node| { - assert_eq!(&expected[idx.get()], graph.node_data(idx)); - assert_eq!(expected[idx.get()], node.data); - true - }); - } - - #[test] - fn each_edge() { - let graph = create_graph(); - let expected = ["AB", "BC", "BD", "DE", "EC", "FB"]; - graph.each_edge(|idx, edge| { - assert_eq!(&expected[idx.get()], graph.edge_data(idx)); - assert_eq!(expected[idx.get()], edge.data); - true - }); - } - - fn test_adjacent_edges(graph: &Graph, - start_index: NodeIndex, - start_data: N, - expected_incoming: &[(E,N)], - expected_outgoing: &[(E,N)]) { - assert!(graph.node_data(start_index) == &start_data); - - let mut counter = 0; - graph.each_incoming_edge(start_index, |edge_index, edge| { - assert!(graph.edge_data(edge_index) == &edge.data); - assert!(counter < expected_incoming.len()); - debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", - counter, expected_incoming[counter], edge_index, edge); - match expected_incoming[counter] { - (ref e, ref n) => { - assert!(e == &edge.data); - assert!(n == graph.node_data(edge.source)); - assert!(start_index == edge.target); - } - } - counter += 1; - true - }); - assert_eq!(counter, expected_incoming.len()); - - let mut counter = 0; - graph.each_outgoing_edge(start_index, |edge_index, edge| { - assert!(graph.edge_data(edge_index) == &edge.data); - assert!(counter < expected_outgoing.len()); - debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", - counter, expected_outgoing[counter], edge_index, edge); - match expected_outgoing[counter] { - (ref e, ref n) => { - assert!(e == &edge.data); - assert!(start_index == edge.source); - assert!(n == graph.node_data(edge.target)); - } - } - counter += 1; - true - }); - assert_eq!(counter, expected_outgoing.len()); - } - - #[test] - fn each_adjacent_from_a() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(0), "A", - &[], - &[("AB", "B")]); - } - - #[test] - fn each_adjacent_from_b() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(1), "B", - &[("FB", "F"), ("AB", "A"),], - &[("BD", "D"), ("BC", "C"),]); - } - - #[test] - fn each_adjacent_from_c() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(2), "C", - &[("EC", "E"), ("BC", "B")], - &[]); - } - - #[test] - fn each_adjacent_from_d() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(3), "D", - &[("BD", "B")], - &[("DE", "E")]); - } -} diff --git a/src/librustc_data_structures/graph/test.rs b/src/librustc_data_structures/graph/test.rs new file mode 100644 index 0000000000000..a26d1d2fbd9e4 --- /dev/null +++ b/src/librustc_data_structures/graph/test.rs @@ -0,0 +1,129 @@ +use graph::*; +use std::fmt::Debug; + +type TestNode = Node<&'static str>; +type TestEdge = Edge<&'static str>; +type TestGraph = Graph<&'static str, &'static str>; + +fn create_graph() -> TestGraph { + let mut graph = Graph::new(); + + // Create a simple graph + // + // A -+> B --> C + // | | ^ + // | v | + // F D --> E + + let a = graph.add_node("A"); + let b = graph.add_node("B"); + let c = graph.add_node("C"); + let d = graph.add_node("D"); + let e = graph.add_node("E"); + let f = graph.add_node("F"); + + graph.add_edge(a, b, "AB"); + graph.add_edge(b, c, "BC"); + graph.add_edge(b, d, "BD"); + graph.add_edge(d, e, "DE"); + graph.add_edge(e, c, "EC"); + graph.add_edge(f, b, "FB"); + + return graph; +} + +#[test] +fn each_node() { + let graph = create_graph(); + let expected = ["A", "B", "C", "D", "E", "F"]; + graph.each_node(|idx, node| { + assert_eq!(&expected[idx.0], graph.node_data(idx)); + assert_eq!(expected[idx.0], node.data); + true + }); +} + +#[test] +fn each_edge() { + let graph = create_graph(); + let expected = ["AB", "BC", "BD", "DE", "EC", "FB"]; + graph.each_edge(|idx, edge| { + assert_eq!(&expected[idx.0], graph.edge_data(idx)); + assert_eq!(expected[idx.0], edge.data); + true + }); +} + +fn test_adjacent_edges(graph: &Graph, + start_index: NodeIndex, + start_data: N, + expected_incoming: &[(E,N)], + expected_outgoing: &[(E,N)]) { + assert!(graph.node_data(start_index) == &start_data); + + let mut counter = 0; + for (edge_index, edge) in graph.incoming_edges(start_index) { + assert!(graph.edge_data(edge_index) == &edge.data); + assert!(counter < expected_incoming.len()); + debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", + counter, expected_incoming[counter], edge_index, edge); + match expected_incoming[counter] { + (ref e, ref n) => { + assert!(e == &edge.data); + assert!(n == graph.node_data(edge.source())); + assert!(start_index == edge.target); + } + } + counter += 1; + } + assert_eq!(counter, expected_incoming.len()); + + let mut counter = 0; + for (edge_index, edge) in graph.outgoing_edges(start_index) { + assert!(graph.edge_data(edge_index) == &edge.data); + assert!(counter < expected_outgoing.len()); + debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", + counter, expected_outgoing[counter], edge_index, edge); + match expected_outgoing[counter] { + (ref e, ref n) => { + assert!(e == &edge.data); + assert!(start_index == edge.source); + assert!(n == graph.node_data(edge.target)); + } + } + counter += 1; + } + assert_eq!(counter, expected_outgoing.len()); +} + +#[test] +fn each_adjacent_from_a() { + let graph = create_graph(); + test_adjacent_edges(&graph, NodeIndex(0), "A", + &[], + &[("AB", "B")]); +} + +#[test] +fn each_adjacent_from_b() { + let graph = create_graph(); + test_adjacent_edges(&graph, NodeIndex(1), "B", + &[("FB", "F"), ("AB", "A"),], + &[("BD", "D"), ("BC", "C"),]); +} + +#[test] +fn each_adjacent_from_c() { + let graph = create_graph(); + test_adjacent_edges(&graph, NodeIndex(2), "C", + &[("EC", "E"), ("BC", "B")], + &[]); +} + +#[test] +fn each_adjacent_from_d() { + let graph = create_graph(); + test_adjacent_edges(&graph, NodeIndex(3), "D", + &[("BD", "B")], + &[("DE", "E")]); +} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 5f2f430df5039..d90a40941cb27 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -33,3 +33,5 @@ extern crate serialize as rustc_serialize; // used by deriving pub mod snapshot_vec; +pub mod graph; +pub mod bitvec; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 3bb737ddc1279..5e2592be44f57 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1886,14 +1886,13 @@ impl LintPass for UnconditionalRecursion { continue; } // add the successors of this node to explore the graph further. - cfg.graph.each_outgoing_edge(idx, |_, edge| { + for (_, edge) in cfg.graph.outgoing_edges(idx) { let target_idx = edge.target(); let target_cfg_id = target_idx.node_id(); if !visited.contains(&target_cfg_id) { work_queue.push(target_idx) } - true - }); + } } // Check the number of self calls because a function that From 71aa0aa8c5ef2bc3b710d4b5203b14ebcebf06a0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 7 Apr 2015 06:12:21 -0400 Subject: [PATCH 56/62] Port to use the new Unify code, which has no UnifyValue trait but is otherwise mostly the same. --- src/librustc/middle/infer/freshen.rs | 2 +- src/librustc/middle/infer/mod.rs | 5 +- src/librustc/middle/infer/unify_key.rs | 48 ++++ src/librustc_data_structures/lib.rs | 1 + .../unify/mod.rs} | 247 +++++++++--------- src/librustc_data_structures/unify/test.rs | 185 +++++++++++++ 6 files changed, 363 insertions(+), 125 deletions(-) create mode 100644 src/librustc/middle/infer/unify_key.rs rename src/{librustc/middle/infer/unify.rs => librustc_data_structures/unify/mod.rs} (64%) create mode 100644 src/librustc_data_structures/unify/test.rs diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index 29f74d12ea3e8..d93d13beec8fc 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -37,7 +37,7 @@ use middle::ty_fold::TypeFolder; use std::collections::hash_map::{self, Entry}; use super::InferCtxt; -use super::unify::ToType; +use super::unify_key::ToType; pub struct TypeFreshener<'a, 'tcx:'a> { infcx: &'a InferCtxt<'a, 'tcx>, diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index b11e25c059d08..30e336a99c2a6 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -29,6 +29,7 @@ use middle::ty::replace_late_bound_regions; use middle::ty::{self, Ty}; use middle::ty_fold::{TypeFolder, TypeFoldable}; use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use rustc_data_structures::unify::{self, UnificationTable}; use std::cell::{RefCell}; use std::fmt; use std::rc::Rc; @@ -41,8 +42,8 @@ use util::ppaux::{Repr, UserString}; use self::combine::CombineFields; use self::region_inference::{RegionVarBindings, RegionSnapshot}; -use self::unify::{ToType, UnificationTable}; use self::error_reporting::ErrorReporting; +use self::unify_key::ToType; pub mod bivariate; pub mod combine; @@ -57,7 +58,7 @@ pub mod resolve; mod freshen; pub mod sub; pub mod type_variable; -pub mod unify; +pub mod unify_key; pub type Bound = Option; pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" diff --git a/src/librustc/middle/infer/unify_key.rs b/src/librustc/middle/infer/unify_key.rs new file mode 100644 index 0000000000000..6b23e2c5029b8 --- /dev/null +++ b/src/librustc/middle/infer/unify_key.rs @@ -0,0 +1,48 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::ty::{self, IntVarValue, Ty}; +use rustc_data_structures::unify::UnifyKey; +use syntax::ast; + +pub trait ToType<'tcx> { + fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>; +} + +impl UnifyKey for ty::IntVid { + type Value = Option; + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } } + fn tag(_: Option) -> &'static str { "IntVid" } +} + +impl<'tcx> ToType<'tcx> for IntVarValue { + fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { + match *self { + ty::IntType(i) => ty::mk_mach_int(tcx, i), + ty::UintType(i) => ty::mk_mach_uint(tcx, i), + } + } +} + +// Floating point type keys + +impl UnifyKey for ty::FloatVid { + type Value = Option; + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } } + fn tag(_: Option) -> &'static str { "FloatVid" } +} + +impl<'tcx> ToType<'tcx> for ast::FloatTy { + fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { + ty::mk_mach_float(tcx, *self) + } +} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index d90a40941cb27..6562a7488984c 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -35,3 +35,4 @@ extern crate serialize as rustc_serialize; // used by deriving pub mod snapshot_vec; pub mod graph; pub mod bitvec; +pub mod unify; diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc_data_structures/unify/mod.rs similarity index 64% rename from src/librustc/middle/infer/unify.rs rename to src/librustc_data_structures/unify/mod.rs index 5aec422713695..aff79e25956f2 100644 --- a/src/librustc/middle/infer/unify.rs +++ b/src/librustc_data_structures/unify/mod.rs @@ -8,16 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::VarValue::*; - use std::marker; - -use middle::ty::{IntVarValue}; -use middle::ty::{self, Ty}; use std::fmt::Debug; use std::marker::PhantomData; -use syntax::ast; -use rustc_data_structures::snapshot_vec as sv; +use snapshot_vec as sv; + +#[cfg(test)] +mod test; /// This trait is implemented by any type that can serve as a type /// variable. We call such variables *unification keys*. For example, @@ -28,9 +25,10 @@ use rustc_data_structures::snapshot_vec as sv; /// `IntVid`, this is `Option`, representing some /// (possibly not yet known) sort of integer. /// -/// Implementations of this trait are at the end of this file. -pub trait UnifyKey : Clone + Debug + PartialEq { - type Value : UnifyValue; +/// Clients are expected to provide implementations of this trait; you +/// can see some examples in the `test` module. +pub trait UnifyKey : Copy + Clone + Debug + PartialEq { + type Value: Clone + PartialEq + Debug; fn index(&self) -> u32; @@ -39,15 +37,6 @@ pub trait UnifyKey : Clone + Debug + PartialEq { fn tag(k: Option) -> &'static str; } -/// Trait for valid types that a type variable can be set to. Note that -/// this is typically not the end type that the value will take on, but -/// rather an `Option` wrapper (where `None` represents a variable -/// whose value is not yet set). -/// -/// Implementations of this trait are at the end of this file. -pub trait UnifyValue : Clone + PartialEq + Debug { -} - /// Value of a unification key. We implement Tarjan's union-find /// algorithm: when two keys are unified, one of them is converted /// into a "redirect" pointing at the other. These redirects form a @@ -57,9 +46,10 @@ pub trait UnifyValue : Clone + PartialEq + Debug { /// time of the algorithm under control. For more information, see /// . #[derive(PartialEq,Clone,Debug)] -pub enum VarValue { - Redirect(K), - Root(K::Value, usize), +pub struct VarValue { + parent: K, // if equal to self, this is a root + value: K::Value, // value assigned (only relevant to root) + rank: u32, // max depth (only relevant to root) } /// Table of unification keys and their values. @@ -76,16 +66,46 @@ pub struct Snapshot { snapshot: sv::Snapshot, } -/// Internal type used to represent the result of a `get()` operation. -/// Conveys the current root and value of the key. -pub struct Node { - pub key: K, - pub value: K::Value, - pub rank: usize, -} - #[derive(Copy, Clone)] -pub struct Delegate(PhantomData); +struct Delegate(PhantomData); + +impl VarValue { + fn new_var(key: K, value: K::Value) -> VarValue { + VarValue::new(key, value, 0) + } + + fn new(parent: K, value: K::Value, rank: u32) -> VarValue { + VarValue { parent: parent, // this is a root + value: value, + rank: rank } + } + + fn redirect(self, to: K) -> VarValue { + VarValue { parent: to, ..self } + } + + fn root(self, rank: u32, value: K::Value) -> VarValue { + VarValue { rank: rank, value: value, ..self } + } + + /// Returns the key of this node. Only valid if this is a root + /// node, which you yourself must ensure. + fn key(&self) -> K { + self.parent + } + + fn parent(&self, self_key: K) -> Option { + self.if_not_self(self.parent, self_key) + } + + fn if_not_self(&self, key: K, self_key: K) -> Option { + if key == self_key { + None + } else { + Some(key) + } + } +} // We can't use V:LatticeValue, much as I would like to, // because frequently the pattern is that V=Option for some @@ -95,7 +115,7 @@ pub struct Delegate(PhantomData); impl UnificationTable { pub fn new() -> UnificationTable { UnificationTable { - values: sv::SnapshotVec::new(), + values: sv::SnapshotVec::new() } } @@ -121,12 +141,13 @@ impl UnificationTable { } pub fn new_key(&mut self, value: K::Value) -> K { - let index = self.values.push(Root(value, 0)); - let k = UnifyKey::from_index(index as u32); + let len = self.values.len(); + let key: K = UnifyKey::from_index(len as u32); + self.values.push(VarValue::new_var(key, value)); debug!("{}: created new key: {:?}", UnifyKey::tag(None::), - k); - k + key); + key } /// Find the root node for `vid`. This uses the standard @@ -135,36 +156,34 @@ impl UnificationTable { /// /// NB. This is a building-block operation and you would probably /// prefer to call `probe` below. - fn get(&mut self, vid: K) -> Node { + fn get(&mut self, vid: K) -> VarValue { let index = vid.index() as usize; - let value = (*self.values.get(index)).clone(); - match value { - Redirect(redirect) => { - let node: Node = self.get(redirect.clone()); - if node.key != redirect { + let mut value: VarValue = self.values.get(index).clone(); + match value.parent(vid) { + Some(redirect) => { + let root: VarValue = self.get(redirect); + if root.key() != redirect { // Path compression - self.values.set(index, Redirect(node.key.clone())); + value.parent = root.key(); + self.values.set(index, value); } - node + root } - Root(value, rank) => { - Node { key: vid, value: value, rank: rank } + None => { + value } } } - fn is_root(&self, key: &K) -> bool { + fn is_root(&self, key: K) -> bool { let index = key.index() as usize; - match *self.values.get(index) { - Redirect(..) => false, - Root(..) => true, - } + self.values.get(index).parent(key).is_none() } /// Sets the value for `vid` to `new_value`. `vid` MUST be a root /// node! This is an internal operation used to impl other things. fn set(&mut self, key: K, new_value: VarValue) { - assert!(self.is_root(&key)); + assert!(self.is_root(key)); debug!("Updating variable {:?} to {:?}", key, new_value); @@ -181,31 +200,36 @@ impl UnificationTable { /// really more of a building block. If the values associated with /// your key are non-trivial, you would probably prefer to call /// `unify_var_var` below. - fn unify(&mut self, node_a: &Node, node_b: &Node, new_value: K::Value) { - debug!("unify(node_a(id={:?}, rank={:?}), node_b(id={:?}, rank={:?}))", - node_a.key, - node_a.rank, - node_b.key, - node_b.rank); - - let (new_root, new_rank) = if node_a.rank > node_b.rank { + fn unify(&mut self, root_a: VarValue, root_b: VarValue, new_value: K::Value) { + debug!("unify(root_a(id={:?}, rank={:?}), root_b(id={:?}, rank={:?}))", + root_a.key(), + root_a.rank, + root_b.key(), + root_b.rank); + + if root_a.rank > root_b.rank { // a has greater rank, so a should become b's parent, // i.e., b should redirect to a. - self.set(node_b.key.clone(), Redirect(node_a.key.clone())); - (node_a.key.clone(), node_a.rank) - } else if node_a.rank < node_b.rank { + self.redirect_root(root_a.rank, root_b, root_a, new_value); + } else if root_a.rank < root_b.rank { // b has greater rank, so a should redirect to b. - self.set(node_a.key.clone(), Redirect(node_b.key.clone())); - (node_b.key.clone(), node_b.rank) + self.redirect_root(root_b.rank, root_a, root_b, new_value); } else { // If equal, redirect one to the other and increment the // other's rank. - assert_eq!(node_a.rank, node_b.rank); - self.set(node_b.key.clone(), Redirect(node_a.key.clone())); - (node_a.key.clone(), node_a.rank + 1) - }; + self.redirect_root(root_a.rank + 1, root_a, root_b, new_value); + } + } - self.set(new_root, Root(new_value, new_rank)); + fn redirect_root(&mut self, + new_rank: u32, + old_root: VarValue, + new_root: VarValue, + new_value: K::Value) { + let old_root_key = old_root.key(); + let new_root_key = new_root.key(); + self.set(old_root_key, old_root.redirect(new_root_key)); + self.set(new_root_key, new_root.root(new_rank, new_value)); } } @@ -213,8 +237,31 @@ impl sv::SnapshotVecDelegate for Delegate { type Value = VarValue; type Undo = (); - fn reverse(_: &mut Vec>, _: ()) { - panic!("Nothing to reverse"); + fn reverse(_: &mut Vec>, _: ()) {} +} + +/////////////////////////////////////////////////////////////////////////// +// Base union-find algorithm, where we are just making setes + +impl<'tcx,K> UnificationTable + where K : UnifyKey, +{ + pub fn union(&mut self, a_id: K, b_id: K) { + let node_a = self.get(a_id); + let node_b = self.get(b_id); + let a_id = node_a.key(); + let b_id = node_b.key(); + if a_id != b_id { + self.unify(node_a, node_b, ()); + } + } + + pub fn find(&mut self, id: K) -> K { + self.get(id).key() + } + + pub fn unioned(&mut self, a_id: K, b_id: K) -> bool { + self.find(a_id) == self.find(b_id) } } @@ -226,7 +273,6 @@ impl sv::SnapshotVecDelegate for Delegate { impl<'tcx,K,V> UnificationTable where K: UnifyKey>, V: Clone+PartialEq, - Option: UnifyValue, { pub fn unify_var_var(&mut self, a_id: K, @@ -235,8 +281,8 @@ impl<'tcx,K,V> UnificationTable { let node_a = self.get(a_id); let node_b = self.get(b_id); - let a_id = node_a.key.clone(); - let b_id = node_b.key.clone(); + let a_id = node_a.key(); + let b_id = node_b.key(); if a_id == b_id { return Ok(()); } @@ -257,7 +303,7 @@ impl<'tcx,K,V> UnificationTable } }; - Ok(self.unify(&node_a, &node_b, combined)) + Ok(self.unify(node_a, node_b, combined)) } /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping @@ -267,12 +313,12 @@ impl<'tcx,K,V> UnificationTable b: V) -> Result<(),(V,V)> { - let node_a = self.get(a_id); - let a_id = node_a.key.clone(); + let mut node_a = self.get(a_id); match node_a.value { None => { - self.set(a_id, Root(Some(b), node_a.rank)); + node_a.value = Some(b); + self.set(node_a.key(), node_a); Ok(()) } @@ -295,46 +341,3 @@ impl<'tcx,K,V> UnificationTable } } -/////////////////////////////////////////////////////////////////////////// - -// Integral type keys - -pub trait ToType<'tcx> { - fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>; -} - -impl UnifyKey for ty::IntVid { - type Value = Option; - fn index(&self) -> u32 { self.index } - fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } } - fn tag(_: Option) -> &'static str { "IntVid" } -} - -impl<'tcx> ToType<'tcx> for IntVarValue { - fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { - match *self { - ty::IntType(i) => ty::mk_mach_int(tcx, i), - ty::UintType(i) => ty::mk_mach_uint(tcx, i), - } - } -} - -impl UnifyValue for Option { } - -// Floating point type keys - -impl UnifyKey for ty::FloatVid { - type Value = Option; - fn index(&self) -> u32 { self.index } - fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } } - fn tag(_: Option) -> &'static str { "FloatVid" } -} - -impl UnifyValue for Option { -} - -impl<'tcx> ToType<'tcx> for ast::FloatTy { - fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { - ty::mk_mach_float(tcx, *self) - } -} diff --git a/src/librustc_data_structures/unify/test.rs b/src/librustc_data_structures/unify/test.rs new file mode 100644 index 0000000000000..d662842a37afd --- /dev/null +++ b/src/librustc_data_structures/unify/test.rs @@ -0,0 +1,185 @@ +#![allow(non_snake_case)] + +extern crate test; +use self::test::Bencher; +use std::collections::HashSet; +use unify::{UnifyKey, UnificationTable}; + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +struct UnitKey(u32); + +impl UnifyKey for UnitKey { + type Value = (); + fn index(&self) -> u32 { self.0 } + fn from_index(u: u32) -> UnitKey { UnitKey(u) } + fn tag(_: Option) -> &'static str { "UnitKey" } +} + +#[test] +fn basic() { + let mut ut: UnificationTable = UnificationTable::new(); + let k1 = ut.new_key(()); + let k2 = ut.new_key(()); + assert_eq!(ut.unioned(k1, k2), false); + ut.union(k1, k2); + assert_eq!(ut.unioned(k1, k2), true); +} + +#[test] +fn big_array() { + let mut ut: UnificationTable = UnificationTable::new(); + let mut keys = Vec::new(); + const MAX: usize = 1 << 15; + + for _ in 0..MAX { + keys.push(ut.new_key(())); + } + + for i in 1..MAX { + let l = keys[i-1]; + let r = keys[i]; + ut.union(l, r); + } + + for i in 0..MAX { + assert!(ut.unioned(keys[0], keys[i])); + } +} + +#[bench] +fn big_array_bench(b: &mut Bencher) { + let mut ut: UnificationTable = UnificationTable::new(); + let mut keys = Vec::new(); + const MAX: usize = 1 << 15; + + for _ in 0..MAX { + keys.push(ut.new_key(())); + } + + + b.iter(|| { + for i in 1..MAX { + let l = keys[i-1]; + let r = keys[i]; + ut.union(l, r); + } + + for i in 0..MAX { + assert!(ut.unioned(keys[0], keys[i])); + } + }) +} + +#[test] +fn even_odd() { + let mut ut: UnificationTable = UnificationTable::new(); + let mut keys = Vec::new(); + const MAX: usize = 1 << 10; + + for i in 0..MAX { + let key = ut.new_key(()); + keys.push(key); + + if i >= 2 { + ut.union(key, keys[i-2]); + } + } + + for i in 1..MAX { + assert!(!ut.unioned(keys[i-1], keys[i])); + } + + for i in 2..MAX { + assert!(ut.unioned(keys[i-2], keys[i])); + } +} + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +struct IntKey(u32); + +impl UnifyKey for IntKey { + type Value = Option; + fn index(&self) -> u32 { self.0 } + fn from_index(u: u32) -> IntKey { IntKey(u) } + fn tag(_: Option) -> &'static str { "IntKey" } +} + +/// Test unifying a key whose value is `Some(_)` with a key whose value is `None`. +/// Afterwards both should be `Some(_)`. +#[test] +fn unify_key_Some_key_None() { + let mut ut: UnificationTable = UnificationTable::new(); + let k1 = ut.new_key(Some(22)); + let k2 = ut.new_key(None); + assert!(ut.unify_var_var(k1, k2).is_ok()); + assert_eq!(ut.probe(k2), Some(22)); + assert_eq!(ut.probe(k1), Some(22)); +} + +/// Test unifying a key whose value is `None` with a key whose value is `Some(_)`. +/// Afterwards both should be `Some(_)`. +#[test] +fn unify_key_None_key_Some() { + let mut ut: UnificationTable = UnificationTable::new(); + let k1 = ut.new_key(Some(22)); + let k2 = ut.new_key(None); + assert!(ut.unify_var_var(k2, k1).is_ok()); + assert_eq!(ut.probe(k2), Some(22)); + assert_eq!(ut.probe(k1), Some(22)); +} + +/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(y)`. +/// This should yield an error. +#[test] +fn unify_key_Some_x_key_Some_y() { + let mut ut: UnificationTable = UnificationTable::new(); + let k1 = ut.new_key(Some(22)); + let k2 = ut.new_key(Some(23)); + assert_eq!(ut.unify_var_var(k1, k2), Err((22, 23))); + assert_eq!(ut.unify_var_var(k2, k1), Err((23, 22))); + assert_eq!(ut.probe(k1), Some(22)); + assert_eq!(ut.probe(k2), Some(23)); +} + +/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(x)`. +/// This should be ok. +#[test] +fn unify_key_Some_x_key_Some_x() { + let mut ut: UnificationTable = UnificationTable::new(); + let k1 = ut.new_key(Some(22)); + let k2 = ut.new_key(Some(22)); + assert!(ut.unify_var_var(k1, k2).is_ok()); + assert_eq!(ut.probe(k1), Some(22)); + assert_eq!(ut.probe(k2), Some(22)); +} + +/// Test unifying a key whose value is `None` with a value is `x`. +/// Afterwards key should be `x`. +#[test] +fn unify_key_None_val() { + let mut ut: UnificationTable = UnificationTable::new(); + let k1 = ut.new_key(None); + assert!(ut.unify_var_value(k1, 22).is_ok()); + assert_eq!(ut.probe(k1), Some(22)); +} + +/// Test unifying a key whose value is `Some(x)` with the value `y`. +/// This should yield an error. +#[test] +fn unify_key_Some_x_val_y() { + let mut ut: UnificationTable = UnificationTable::new(); + let k1 = ut.new_key(Some(22)); + assert_eq!(ut.unify_var_value(k1, 23), Err((22, 23))); + assert_eq!(ut.probe(k1), Some(22)); +} + +/// Test unifying a key whose value is `Some(x)` with the value `x`. +/// This should be ok. +#[test] +fn unify_key_Some_x_val_x() { + let mut ut: UnificationTable = UnificationTable::new(); + let k1 = ut.new_key(Some(22)); + assert!(ut.unify_var_value(k1, 22).is_ok()); + assert_eq!(ut.probe(k1), Some(22)); +} + From ee94ee72cf24d23efb020bfa060891a47b802ffd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Apr 2015 18:53:56 -0400 Subject: [PATCH 57/62] Add licenses. --- src/librustc_data_structures/bitvec.rs | 10 ++++++++++ src/librustc_data_structures/graph/test.rs | 10 ++++++++++ src/librustc_data_structures/lib.rs | 2 +- src/librustc_data_structures/unify/test.rs | 10 ++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index f5924ef5a3f63..983601771a02f 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -1,3 +1,13 @@ +// 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::iter; /// A very simple BitVector type. diff --git a/src/librustc_data_structures/graph/test.rs b/src/librustc_data_structures/graph/test.rs index a26d1d2fbd9e4..33b2edd2e106d 100644 --- a/src/librustc_data_structures/graph/test.rs +++ b/src/librustc_data_structures/graph/test.rs @@ -1,3 +1,13 @@ +// 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 graph::*; use std::fmt::Debug; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 6562a7488984c..dc376deebc113 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -27,7 +27,7 @@ html_root_url = "http://doc.rust-lang.org/nightly/")] #![feature(rustc_private)] -#![feature(test)] +#![cfg_attr(test, feature(test))] #[macro_use] extern crate log; extern crate serialize as rustc_serialize; // used by deriving diff --git a/src/librustc_data_structures/unify/test.rs b/src/librustc_data_structures/unify/test.rs index d662842a37afd..dbe3cfc7a48a9 100644 --- a/src/librustc_data_structures/unify/test.rs +++ b/src/librustc_data_structures/unify/test.rs @@ -1,3 +1,13 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + #![allow(non_snake_case)] extern crate test; From ead463155a4d1f64419f3731652d48ab9b2ef4ed Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Apr 2015 19:31:20 -0400 Subject: [PATCH 58/62] Address nits --- src/librustc_data_structures/unify/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_data_structures/unify/mod.rs b/src/librustc_data_structures/unify/mod.rs index aff79e25956f2..7036c010c6580 100644 --- a/src/librustc_data_structures/unify/mod.rs +++ b/src/librustc_data_structures/unify/mod.rs @@ -241,7 +241,7 @@ impl sv::SnapshotVecDelegate for Delegate { } /////////////////////////////////////////////////////////////////////////// -// Base union-find algorithm, where we are just making setes +// Base union-find algorithm, where we are just making sets impl<'tcx,K> UnificationTable where K : UnifyKey, From 0e0c841bd5f7bbf3f5788e9e96aa682e6e7726b2 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 9 Apr 2015 11:51:46 -0700 Subject: [PATCH 59/62] Nightly gets LLVM assertions --- configure | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 97c998a5cda3c..4f809237bf85a 100755 --- a/configure +++ b/configure @@ -617,11 +617,15 @@ fi step_msg "validating $CFG_SELF args" validate_opt -# Validate the release channel +# Validate the release channel, and configure options case "$CFG_RELEASE_CHANNEL" in - (dev | nightly | beta | stable) + nightly ) + msg "overriding settings for $CFG_RELEASE_CHANNEL" + CFG_ENABLE_LLVM_ASSERTIONS=1 ;; - (*) + dev | beta | stable) + ;; + *) err "release channel must be 'dev', 'nightly', 'beta' or 'stable'" ;; esac From ea731797b821c3347be72fefcba32d48e04d27d0 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 10 Apr 2015 02:09:19 +0530 Subject: [PATCH 60/62] fixup windows std_misc --- src/test/run-pass/issue-13259-windows-tcb-trash.rs | 2 +- src/test/run-pass/x86stdcall2.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/run-pass/issue-13259-windows-tcb-trash.rs b/src/test/run-pass/issue-13259-windows-tcb-trash.rs index 34960b264567d..9ebbddf5141b7 100644 --- a/src/test/run-pass/issue-13259-windows-tcb-trash.rs +++ b/src/test/run-pass/issue-13259-windows-tcb-trash.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#![feature(libc)] +#![feature(libc, std_misc)] extern crate libc; diff --git a/src/test/run-pass/x86stdcall2.rs b/src/test/run-pass/x86stdcall2.rs index 7b15531dacc33..62da9c9d14be2 100644 --- a/src/test/run-pass/x86stdcall2.rs +++ b/src/test/run-pass/x86stdcall2.rs @@ -10,6 +10,8 @@ // pretty-expanded FIXME #23616 +#![feature(std_misc)] + pub type HANDLE = u32; pub type DWORD = u32; pub type SIZE_T = u32; From bf88539cc94db17f5402798feb2a9db28e9be39c Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 9 Apr 2015 12:47:08 -0400 Subject: [PATCH 61/62] TRPL: new introduction --- src/doc/trpl/README.md | 203 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 178 insertions(+), 25 deletions(-) diff --git a/src/doc/trpl/README.md b/src/doc/trpl/README.md index 6e8d394afa5b1..b2e1a6ec0bc19 100644 --- a/src/doc/trpl/README.md +++ b/src/doc/trpl/README.md @@ -1,39 +1,192 @@ % The Rust Programming Language -Welcome! This book will teach you about [the Rust Programming -Language](http://www.rust-lang.org/). Rust is a modern systems programming -language focusing on safety and speed. It accomplishes these goals by being -memory safe without using garbage collection. +Welcome! This book will teach you about the [Rust Programming Language][rust]. +Rust is a systems programming language focused on three goals: safety, speed, +and concurrency. It maintains these goals without having a garbage collector, +making it a useful language for a number of use cases other languages aren’t +good at: embedding in other languages, programs with specific space and time +requirements, and writing low-level code, like device drivers and operating +systems. It improves on current languages targeting this space by having a +number of compile-time safety checks that produce no runtime overhead, while +eliminating all data races. Rust also aims to achieve ‘zero-cost abstrations’ +even though some of these abstractions feel like those of a high-level +language. Even then, Rust still allows precise control like a low-level +language would. -"The Rust Programming Language" is split into three sections, which you can -navigate through the menu on the left. +[rust]: http://rust-lang.org - +“The Rust Programming Language” is split into seven sections. This introduction +is the first. After this: -This section is a linear introduction to the basic syntax and semantics of -Rust. It has individual sections on each part of Rust's syntax. +* [Getting started][gs] - Set up your computer for Rust development. +* [Learn Rust][lr] - Learn Rust programming through small projects. +* [Effective Rust][er] - Higher-level concepts for writing excellent Rust code. +* [Syntax and Semantics][ss] - Each bit of Rust, broken down into small chunks. +* [Nightly Rust][nr] - Cutting-edge features that aren’t in stable builds yet. +* [Glossary][gl] - A reference of terms used in the book. -After reading "Basics," you will have a good foundation to learn more about -Rust, and can write very simple programs. +[gs]: getting-started.html +[lr]: learn-rust.html +[er]: effective-rust.html +[ss]: syntax-and-semantics.html +[nr]: nightly-rust.html +[gl]: glossary.html -

Intermediate

+After reading this introduction, you’ll want to dive into either ‘Learn Rust’ +or ‘Syntax and Semantics’, depending on your preference: ‘Learn Rust’ if you +want to dive in with a project, or ‘Syntax and Semantics’ if you prefer to +start small, and learn a single concept thoroughly before moving onto the next. +Copious cross-linking connects these parts together. -This section contains individual chapters, which are self-contained. They focus -on specific topics, and can be read in any order. +## A brief introduction to Rust -After reading "Intermediate," you will have a solid understanding of Rust, -and will be able to understand most Rust code and write more complex programs. +Is Rust a language you might be interested in? Let’s examine a few small code +samples to show off a few of its strengths. -

Advanced

+The main concept that makes Rust unique is called ‘ownership’. Consider this +small example: -In a similar fashion to "Intermediate," this section is full of individual, -deep-dive chapters, which stand alone and can be read in any order. These -chapters focus on Rust's most complex features. +```rust +fn main() { + let mut x = vec!["Hello", "world"]; +} +``` -

Unstable

+This program makes a [variable binding][var] named `x`. The value of this +binding is a `Vec`, a ‘vector’, that we create through a [macro][macro] +defined in the standard library. This macro is called `vec`, and we invoke +macros with a `!`. This follows a general principle of Rust: make things +explicit. Macros can do significantly more complicated things than function +calls, and so they’re visually distinct. The `!` also helps with parsing, +making tooling easier to write, which is also important. -In a similar fashion to "Intermediate," this section is full of individual, -deep-dive chapters, which stand alone and can be read in any order. +We used `mut` to make `x` mutable: bindings are immutable by default in Rust. +We’ll be mutating this vector later in the example. -This chapter contains things that are only available on the nightly channel of -Rust. +It’s also worth noting that we didn’t need a type annotation here: while Rust +is statically typed, we didn’t need to explicitly annotate the type. Rust has +type inference to balance out the power of static typing with the verbosity of +annotating types. + +Rust prefers stack allocation to heap allocation: `x` is placed directly on the +stack. However, the `Vec` type allocates space for the elements of the +vector on the heap. If you’re not familiar with this distinction, you can +ignore it for now, or check out [‘The Stack and the Heap’][heap]. As a systems +programming language, Rust gives you the ability to control how your memory is +allocated, but when we’re getting started, it’s less of a big deal. + +[var]: variable-bindings.html +[macro]: macros.html +[heap]: the-stack-and-the-heap.html + +Earlier, we mentioned that ‘ownership’ is the key new concept in Rust. In Rust +parlance, `x` is said to ‘own’ the vector. This means that when `x` goes out of +scope, the vector’s memory will be de-allocated. This is done deterministically +by the Rust compiler, rather than through a mechanism such as a garbage +collector. In other words, in Rust, you don’t call functions like `malloc` and +`free` yourself: the compiler statically determines when you need to allocate +or deallocate memory, and inserts those calls itself. To err is to be human, +but compilers never forget. + +Let’s add another line to our example: + +```rust +fn main() { + let mut x = vec!["Hello", "world"]; + + let y = &x[0]; +} +``` + +We’ve introduced another binding, `y`. In this case, `y` is a ‘reference’ to +the first element of the vector. Rust’s references are similar to pointers in +other languages, but with additional compile-time safety checks. References +interact with the ownership system by [‘borrowing’][borrowing] what they point +to, rather than owning it. The difference is, when the reference goes out of +scope, it will not deallocate the underlying memory. If it did, we’d +de-allocate twice, which is bad! + +[borrowing]: references-and-borrowing.html + +Let’s add a third line. It looks innocent enough, but causes a compiler error: + +```rust,ignore +fn main() { + let mut x = vec!["Hello", "world"]; + + let y = &x[0]; + + x.push(4); +} +``` + +`push` is a method on vectors that appends another element to the end of the +vector. When we try to compile this program, we get an error: + +```text +error: cannot borrow `x` as mutable because it is also borrowed as immutable + x.push(4); + ^ +note: previous borrow of `x` occurs here; the immutable borrow prevents +subsequent moves or mutable borrows of `x` until the borrow ends + let y = &x[0]; + ^ +note: previous borrow ends here +fn main() { + +} +^ +``` + +Whew! The Rust compiler gives quite detailed errors at times, and this is one +of those times. As the error explains, while we made our binding mutable, we +still cannot call `push`. This is because we already have a reference to an +element of the vector, `y`. Mutating something while another reference exists +is dangerous, because we may invalidate the reference. In this specific case, +when we create the vector, we may have only allocated space for three elements. +Adding a fourth would mean allocating a new chunk of memory for all those elements, +copying the old values over, and updating the internal pointer to that memory. +That all works just fine. The problem is that `y` wouldn’t get updated, and so +we’d have a ‘dangling pointer’. That’s bad. Any use of `y` would be an error in +this case, and so the compiler has caught this for us. + +So how do we solve this problem? There are two approaches we can take. The first +is making a copy rather than using a reference: + +```rust +fn main() { + let mut x = vec!["Hello", "world"]; + + let y = x[0].clone(); + + x.push(4); +} +``` + +Rust has [move semantics][move] by default, so if we want to make a copy of some +data, we call the `clone()` method. In this example, `y` is no longer a reference +to the vector stored in `x`, but a copy of its first element, `"hello"`. Now +that we don’t have a reference, our `push()` works just fine. + +[move]: move-semantics.html + +If we truly want a reference, we need the other option: ensure that our reference +goes out of scope before we try to do the mutation. That looks like this: + +```rust +fn main() { + let mut x = vec!["Hello", "world"]; + + { + let y = &x[0]; + } + + x.push(4); +} +``` + +We created an inner scope with an additional set of curly braces. `y` will go out of +scope before we call `push()`, and so we’re all good. + +This concept of ownership isn’t just good for preventing danging pointers, but an +entire set of related problems, like iterator invalidation, concurrency, and more. From 5a906615886743f3eb6d90bd837e8d11a5e19584 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 6 Apr 2015 14:25:39 -0400 Subject: [PATCH 62/62] Add examples for Convert --- src/libcore/convert.rs | 58 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 85b648bbd5980..f874d4f6a2796 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -10,15 +10,35 @@ //! Traits for conversions between types. //! -//! The traits in this module provide a general way to talk about -//! conversions from one type to another. They follow the standard -//! Rust conventions of `as`/`to`/`into`/`from`. +//! The traits in this module provide a general way to talk about conversions from one type to +//! another. They follow the standard Rust conventions of `as`/`to`/`into`/`from`. +//! +//! Like many traits, these are often used as bounds for generic functions, to support arguments of +//! multiple types. +//! +//! See each trait for usage examples. #![stable(feature = "rust1", since = "1.0.0")] use marker::Sized; /// A cheap, reference-to-reference conversion. +/// +/// # Examples +/// +/// Both `String` and `&str` implement `AsRef`: +/// +/// ``` +/// fn is_hello>(s: T) { +/// assert_eq!("hello", s.as_ref()); +/// } +/// +/// let s = "hello"; +/// is_hello(s); +/// +/// let s = "hello".to_string(); +/// is_hello(s); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRef { /// Performs the conversion. @@ -34,8 +54,21 @@ pub trait AsMut { fn as_mut(&mut self) -> &mut T; } -/// A conversion that consumes `self`, which may or may not be -/// expensive. +/// A conversion that consumes `self`, which may or may not be expensive. +/// +/// # Examples +/// +/// `String` implements `Into>`: +/// +/// ``` +/// fn is_hello>>(s: T) { +/// let bytes = b"hello".to_vec(); +/// assert_eq!(bytes, s.into()); +/// } +/// +/// let s = "hello".to_string(); +/// is_hello(s); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Into: Sized { /// Performs the conversion. @@ -44,6 +77,21 @@ pub trait Into: Sized { } /// Construct `Self` via a conversion. +/// +/// # Examples +/// +/// `Vec` implements `From`: +/// +/// ``` +/// fn is_hello>(v: T) { +/// let string = "hello".to_string(); +/// +/// assert_eq!(string, v.from()); +/// } +/// +/// let b = b"hello".to_vec(); +/// is_hello(b); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait From { /// Performs the conversion.

Basics