diff --git a/cargo b/cargo index c416fb60b11ec..770512b08fb29 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 +Subproject commit 770512b08fb2985aed6f06311f1c58ed587fa259 diff --git a/src/Cargo.lock b/src/Cargo.lock index 62b853480394f..80a8596a499c7 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -269,7 +269,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mdbook" -version = "0.0.18" +version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -425,7 +425,7 @@ name = "rustbook" version = "0.1.0" dependencies = [ "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "mdbook 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1004,7 +1004,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4732c563b9a21a406565c4747daa7b46742f082911ae4753f390dc9ec7ee1a97" "checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" "checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" -"checksum mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "06a68e8738e42b38a02755d3ce5fa12d559e17acb238e4326cbc3cc056e65280" +"checksum mdbook 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "2598843aeda0c5bb2e8e4d714564f1c3fc40f7844157e34563bf96ae3866b56e" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 2f7757fb1d5ba..1ce99eb893efe 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -4,10 +4,6 @@ This is an in-progress README which is targeted at helping to explain how Rust is bootstrapped and in general some of the technical details of the build system. -> **Note**: This build system is currently under active development and is not -> intended to be the primarily used one just yet. The makefiles are currently -> the ones that are still "guaranteed to work" as much as possible at least. - ## Using rustbuild The rustbuild build system has a primary entry point, a top level `x.py` script: diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index f8f641060c442..a439e79fce538 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -78,14 +78,6 @@ pub fn linkcheck(build: &Build, host: &str) { pub fn cargotest(build: &Build, stage: u32, host: &str) { let ref compiler = Compiler::new(stage, host); - // Configure PATH to find the right rustc. NB. we have to use PATH - // and not RUSTC because the Cargo test suite has tests that will - // fail if rustc is not spelled `rustc`. - let path = build.sysroot(compiler).join("bin"); - let old_path = ::std::env::var("PATH").expect(""); - let sep = if cfg!(windows) { ";" } else {":" }; - let ref newpath = format!("{}{}{}", path.display(), sep, old_path); - // Note that this is a short, cryptic, and not scoped directory name. This // is currently to minimize the length of path on Windows where we otherwise // quickly run into path name limit constraints. @@ -95,11 +87,49 @@ pub fn cargotest(build: &Build, stage: u32, host: &str) { let _time = util::timeit(); let mut cmd = Command::new(build.tool(&Compiler::new(0, host), "cargotest")); build.prepare_tool_cmd(compiler, &mut cmd); - build.run(cmd.env("PATH", newpath) - .arg(&build.cargo) + build.run(cmd.arg(&build.cargo) .arg(&out_dir)); } +/// Runs `cargo test` for `cargo` packaged with Rust. +pub fn cargo(build: &Build, stage: u32, host: &str) { + let ref compiler = Compiler::new(stage, host); + + // Configure PATH to find the right rustc. NB. we have to use PATH + // and not RUSTC because the Cargo test suite has tests that will + // fail if rustc is not spelled `rustc`. + let path = build.sysroot(compiler).join("bin"); + let old_path = ::std::env::var("PATH").expect(""); + let sep = if cfg!(windows) { ";" } else {":" }; + let ref newpath = format!("{}{}{}", path.display(), sep, old_path); + + let mut cargo = build.cargo(compiler, Mode::Tool, host, "test"); + cargo.arg("--manifest-path").arg(build.src.join("cargo/Cargo.toml")); + + // Don't build tests dynamically, just a pain to work with + cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + + // Don't run cross-compile tests, we may not have cross-compiled libstd libs + // available. + cargo.env("CFG_DISABLE_CROSS_TESTS", "1"); + + // When being tested Cargo will at some point call `nmake.exe` on Windows + // MSVC. Unfortunately `nmake` will read these two environment variables + // below and try to intepret them. We're likely being run, however, from + // MSYS `make` which uses the same variables. + // + // As a result, to prevent confusion and errors, we remove these variables + // from our environment to prevent passing MSYS make flags to nmake, causing + // it to blow up. + if cfg!(target_env = "msvc") { + cargo.env_remove("MAKE"); + cargo.env_remove("MAKEFLAGS"); + } + + + build.run(cargo.env("PATH", newpath)); +} + /// Runs the `tidy` tool as compiled in `stage` by the `host` compiler. /// /// This tool in `src/tools` checks up on various bits and pieces of style and diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 457ac825832ce..a5df741e2bfc8 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -55,6 +55,7 @@ check: check-aux: $(Q)$(BOOTSTRAP) test \ src/tools/cargotest \ + cargo \ src/test/pretty \ src/test/run-pass/pretty \ src/test/run-fail/pretty \ diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 17902a39df1e8..d811e1122c42f 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -470,6 +470,10 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|s| s.name("librustc")) .host(true) .run(move |s| check::cargotest(build, s.stage, s.target)); + rules.test("check-cargo", "cargo") + .dep(|s| s.name("tool-cargo")) + .host(true) + .run(move |s| check::cargo(build, s.stage, s.target)); rules.test("check-tidy", "src/tools/tidy") .dep(|s| s.name("tool-tidy").stage(0)) .default(true) diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index b986c0275502c..fb0b852d10271 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -1442,6 +1442,7 @@ impl<'a, K, V> Clone for Values<'a, K, V> { } } +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> Iterator for Range<'a, K, V> { type Item = (&'a K, &'a V); @@ -1517,6 +1518,7 @@ impl<'a, K, V> Range<'a, K, V> { } } +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> DoubleEndedIterator for Range<'a, K, V> { fn next_back(&mut self) -> Option<(&'a K, &'a V)> { if self.front == self.back { @@ -1562,6 +1564,7 @@ impl<'a, K, V> Range<'a, K, V> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for Range<'a, K, V> {} +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> Clone for Range<'a, K, V> { fn clone(&self) -> Range<'a, K, V> { Range { @@ -1571,6 +1574,7 @@ impl<'a, K, V> Clone for Range<'a, K, V> { } } +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> Iterator for RangeMut<'a, K, V> { type Item = (&'a K, &'a mut V); @@ -1615,6 +1619,7 @@ impl<'a, K, V> RangeMut<'a, K, V> { } } +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> { if self.front == self.back { diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index ffca6964c5fdf..dfff44e30c597 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -941,11 +941,14 @@ impl ExactSizeIterator for IntoIter { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, T> Clone for Range<'a, T> { fn clone(&self) -> Range<'a, T> { Range { iter: self.iter.clone() } } } + +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, T> Iterator for Range<'a, T> { type Item = &'a T; @@ -953,6 +956,8 @@ impl<'a, T> Iterator for Range<'a, T> { self.iter.next().map(|(k, _)| k) } } + +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, T> DoubleEndedIterator for Range<'a, T> { fn next_back(&mut self) -> Option<&'a T> { self.iter.next_back().map(|(k, _)| k) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 2ce3b92843bd7..2a73a78adbe5f 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -2272,7 +2272,7 @@ macro_rules! __impl_slice_eq1 { __impl_slice_eq1! { $Lhs, $Rhs, Sized } }; ($Lhs: ty, $Rhs: ty, $Bound: ident) => { - #[stable(feature = "vec-deque-partial-eq-slice", since = "1.16.0")] + #[stable(feature = "vec-deque-partial-eq-slice", since = "1.17.0")] impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { fn eq(&self, other: &$Rhs) -> bool { if self.len() != other.len() { diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 2a28d108df77d..bf4e414d41684 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -150,7 +150,7 @@ macro_rules! assert_eq { /// assert_ne!(a, b, "we are testing that the values are not equal"); /// ``` #[macro_export] -#[stable(feature = "assert_ne", since = "1.12.0")] +#[stable(feature = "assert_ne", since = "1.13.0")] macro_rules! assert_ne { ($left:expr, $right:expr) => ({ match (&$left, &$right) { @@ -268,7 +268,7 @@ macro_rules! debug_assert_eq { /// debug_assert_ne!(a, b); /// ``` #[macro_export] -#[stable(feature = "assert_ne", since = "1.12.0")] +#[stable(feature = "assert_ne", since = "1.13.0")] macro_rules! debug_assert_ne { ($($arg:tt)*) => (if cfg!(debug_assertions) { assert_ne!($($arg)*); }) } @@ -379,7 +379,7 @@ macro_rules! try { /// assert_eq!(v, b"s = \"abc 123\""); /// ``` #[macro_export] -#[stable(feature = "core", since = "1.6.0")] +#[stable(feature = "rust1", since = "1.0.0")] macro_rules! write { ($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*))) } @@ -479,7 +479,7 @@ macro_rules! writeln { /// } /// ``` #[macro_export] -#[stable(feature = "core", since = "1.6.0")] +#[stable(feature = "rust1", since = "1.0.0")] macro_rules! unreachable { () => ({ panic!("internal error: entered unreachable code") @@ -540,7 +540,7 @@ macro_rules! unreachable { /// } /// ``` #[macro_export] -#[stable(feature = "core", since = "1.6.0")] +#[stable(feature = "rust1", since = "1.0.0")] macro_rules! unimplemented { () => (panic!("not yet implemented")) } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index a1bafe113e415..4d8b31a33cdef 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1597,9 +1597,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // generic so we don't have to do anything quite this // terrible. let trace = TypeTrace::dummy(self.tcx); - self.equate(true, trace, a, b).map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.equate(true, trace, a, b).map(|InferOk { obligations: _, .. }| { + // We can intentionally ignore obligations here, since + // this is part of a simple test for general + // "equatability". However, it's not entirely clear + // that we *ought* to be, perhaps a better thing would + // be to use a mini-fulfillment context or something + // like that. }) }) } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 383fab3fcd766..a943ef30e534b 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -55,16 +55,15 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, debug!("overlap: b_impl_header={:?}", b_impl_header); // Do `a` and `b` unify? If not, no overlap. - match selcx.infcx().eq_impl_headers(true, + let obligations = match selcx.infcx().eq_impl_headers(true, &ObligationCause::dummy(), &a_impl_header, &b_impl_header) { Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + obligations } Err(_) => return None - } + }; debug!("overlap: unification check succeeded"); @@ -78,6 +77,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, .map(|p| Obligation { cause: ObligationCause::dummy(), recursion_depth: 0, predicate: p }) + .chain(obligations) .find(|o| !selcx.evaluate_obligation(o)); if let Some(failing_obligation) = opt_failing_obligation { diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index d771be077ae3a..d49affa3e872c 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -184,6 +184,16 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { }); } + pub fn register_predicate_obligations(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + obligations: Vec>) + { + for obligation in obligations { + self.register_predicate_obligation(infcx, obligation); + } + } + + pub fn region_obligations(&self, body_id: ast::NodeId) -> &[RegionObligation<'tcx>] diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 92b7c736d42fd..5f02688be34bc 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -218,7 +218,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, -> Result<&'tcx Substs<'tcx>, ()> { let selcx = &mut SelectionContext::new(&infcx); let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl); - let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx, + let (target_trait_ref, mut obligations) = impl_trait_ref_and_oblig(selcx, target_impl, target_substs); @@ -227,9 +227,8 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, &ObligationCause::dummy(), source_trait_ref, target_trait_ref) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()) + Ok(InferOk { obligations: o, .. }) => { + obligations.extend(o); } Err(_) => { debug!("fulfill_implication: {:?} does not unify with {:?}", diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 44e291a44c777..7447fba3038ea 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -376,7 +376,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { match self.sub(t1, t2) { Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) once obligations are being propagated, assert the right thing. + // None of these tests should require nested obligations: assert!(obligations.is_empty()); } Err(ref e) => { @@ -400,7 +400,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) { match self.lub(t1, t2) { Ok(InferOk { obligations, value: t }) => { - // FIXME(#32730) once obligations are being propagated, assert the right thing. + // None of these tests should require nested obligations: assert!(obligations.is_empty()); self.assert_eq(t, t_lub); @@ -415,7 +415,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { match self.glb(t1, t2) { Err(e) => panic!("unexpected error computing LUB: {:?}", e), Ok(InferOk { obligations, value: t }) => { - // FIXME(#32730) once obligations are being propagated, assert the right thing. + // None of these tests should require nested obligations: assert!(obligations.is_empty()); self.assert_eq(t, t_glb); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 8a6853461a5e8..ae70049cc5bdc 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -294,10 +294,9 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("compare_impl_method: trait_fty={:?}", trait_fty); let sub_result = infcx.sub_types(false, &cause, impl_fty, trait_fty) - .map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - }); + .map(|InferOk { obligations, .. }| { + inh.register_predicates(obligations); + }); if let Err(terr) = sub_result { debug!("sub_types failed: impl ty {:?}, trait ty {:?}", diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 9f41373dab1b7..b71ff58ccec33 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -82,7 +82,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( // check that the impl type can be made to match the trait type. let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id); - tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|ref infcx| { let tcx = infcx.tcx; let mut fulfillment_cx = traits::FulfillmentContext::new(); @@ -97,8 +97,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id); match infcx.eq_types(true, cause, named_type, fresh_impl_self_ty) { Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + fulfillment_cx.register_predicate_obligations(infcx, obligations); } Err(_) => { let item_span = tcx.hir.span(self_type_node_id); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index e9a606dc0ab1d..0754b52cf280a 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -109,7 +109,7 @@ use rustc::infer::InferOk; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::Providers; -use rustc::traits::{ObligationCause, ObligationCauseCode, Reveal}; +use rustc::traits::{FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal}; use session::config; use util::common::time; @@ -153,15 +153,22 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>) -> bool { - tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt((), Reveal::UserFacing).enter(|ref infcx| { + let mut fulfill_cx = FulfillmentContext::new(); match infcx.eq_types(false, &cause, expected, actual) { Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - true + fulfill_cx.register_predicate_obligations(infcx, obligations); } Err(err) => { infcx.report_mismatched_types(cause, expected, actual, err).emit(); + return false; + } + } + + match fulfill_cx.select_all_or_error(infcx) { + Ok(()) => true, + Err(errors) => { + infcx.report_fulfillment_errors(&errors); false } } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 3d80120f6b2bd..9ff7d7467338b 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -216,7 +216,7 @@ impl<'a> From<&'a str> for Box { } } -#[stable(feature = "never_error", since = "1.18.0")] +#[unstable(feature = "never_type_impls", issue = "35121")] impl Error for ! { fn description(&self) -> &str { *self } } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index db446d88900c1..22889b5de4c2a 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -10,11 +10,18 @@ //! Cross-platform path manipulation. //! -//! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`] +//! This module provides two types, [`PathBuf`] and [`Path`] (akin to [`String`] //! and [`str`]), for working with paths abstractly. These types are thin wrappers //! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly //! on strings according to the local platform's path syntax. //! +//! Paths can be parsed into [`Component`]s by iterating over the structure +//! returned by the [`components`] method on [`Path`]. [`Component`]s roughly +//! correspond to the substrings between path separators (`/` or `\`). You can +//! reconstruct an equivalent path from components with the [`push`] method on +//! [`PathBuf`]; note that the paths may differ syntactically by the +//! normalization described in the documentation for the [`components`] method. +//! //! ## Simple usage //! //! Path manipulation includes both parsing components from slices and building @@ -50,62 +57,11 @@ //! path.set_extension("dll"); //! ``` //! -//! ## Path components and normalization -//! -//! The path APIs are built around the notion of "components", which roughly -//! correspond to the substrings between path separators (`/` and, on Windows, -//! `\`). The APIs for path parsing are largely specified in terms of the path's -//! components, so it's important to clearly understand how those are -//! determined. -//! -//! A path can always be reconstructed into an *equivalent* path by -//! putting together its components via `push`. Syntactically, the -//! paths may differ by the normalization described below. -//! -//! ### Component types -//! -//! Components come in several types: -//! -//! * Normal components are the default: standard references to files or -//! directories. The path `a/b` has two normal components, `a` and `b`. -//! -//! * Current directory components represent the `.` character. For example, -//! `./a` has a current directory component and a normal component `a`. -//! -//! * The root directory component represents a separator that designates -//! starting from root. For example, `/a/b` has a root directory component -//! followed by normal components `a` and `b`. -//! -//! On Windows, an additional component type comes into play: -//! -//! * Prefix components, of which there is a large variety. For example, `C:` -//! and `\\server\share` are prefixes. The path `C:windows` has a prefix -//! component `C:` and a normal component `windows`; the path `C:\windows` has a -//! prefix component `C:`, a root directory component, and a normal component -//! `windows`. -//! -//! ### Normalization -//! -//! Aside from splitting on the separator(s), there is a small amount of -//! "normalization": -//! -//! * Repeated separators are ignored: `a/b` and `a//b` both have components `a` -//! and `b`. -//! -//! * Occurrences of `.` are normalized away, *except* if they are at -//! the beginning of the path (in which case they are often meaningful -//! in terms of path searching). So, for example, `a/./b`, `a/b/`, -//! `/a/b/.` and `a/b` all have components `a` and `b`, but `./a/b` -//! has a leading current directory component. -//! -//! No other normalization takes place by default. In particular, -//! `a/c` and `a/b/../c` are distinct, to account for the possibility -//! that `b` is a symbolic link (so its parent isn't `a`). Further -//! normalization is possible to build on top of the components APIs, -//! and will be included in this library in the near future. -//! +//! [`Component`]: ../../std/path/enum.Component.html +//! [`components`]: ../../std/path/struct.Path.html#method.components //! [`PathBuf`]: ../../std/path/struct.PathBuf.html //! [`Path`]: ../../std/path/struct.Path.html +//! [`push`]: ../../std/path/struct.PathBuf.html#method.push //! [`String`]: ../../std/string/struct.String.html //! [`str`]: ../../std/primitive.str.html //! [`OsString`]: ../../std/ffi/struct.OsString.html @@ -143,36 +99,81 @@ use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; // Windows Prefixes //////////////////////////////////////////////////////////////////////////////// -/// Path prefixes (Windows only). +/// Windows path prefixes, e.g. `C:` or `\\server\share`. /// -/// Windows uses a variety of path styles, including references to drive -/// volumes (like `C:`), network shared folders (like `\\server\share`) and -/// others. In addition, some path prefixes are "verbatim", in which case -/// `/` is *not* treated as a separator and essentially no normalization is -/// performed. +/// Windows uses a variety of path prefix styles, including references to drive +/// volumes (like `C:`), network shared folders (like `\\server\share`), and +/// others. In addition, some path prefixes are "verbatim" (i.e. prefixed with +/// `\\?\`), in which case `/` is *not* treated as a separator and essentially +/// no normalization is performed. +/// +/// # Examples +/// +/// ``` +/// use std::path::{Component, Path, Prefix}; +/// use std::path::Prefix::*; +/// use std::ffi::OsStr; +/// +/// fn get_path_prefix(s: &str) -> Prefix { +/// let path = Path::new(s); +/// match path.components().next().unwrap() { +/// Component::Prefix(prefix_component) => prefix_component.kind(), +/// _ => panic!(), +/// } +/// } +/// +/// # if cfg!(windows) { +/// assert_eq!(Verbatim(OsStr::new("pictures")), +/// get_path_prefix(r"\\?\pictures\kittens")); +/// assert_eq!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")), +/// get_path_prefix(r"\\?\UNC\server\share")); +/// assert_eq!(VerbatimDisk('C' as u8), get_path_prefix(r"\\?\c:\")); +/// assert_eq!(DeviceNS(OsStr::new("BrainInterface")), +/// get_path_prefix(r"\\.\BrainInterface")); +/// assert_eq!(UNC(OsStr::new("server"), OsStr::new("share")), +/// get_path_prefix(r"\\server\share")); +/// assert_eq!(Disk('C' as u8), get_path_prefix(r"C:\Users\Rust\Pictures\Ferris")); +/// # } +/// ``` #[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Prefix<'a> { - /// Prefix `\\?\`, together with the given component immediately following it. + /// Verbatim prefix, e.g. `\\?\cat_pics`. + /// + /// Verbatim prefixes consist of `\\?\` immediately followed by the given + /// component. #[stable(feature = "rust1", since = "1.0.0")] Verbatim(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), - /// Prefix `\\?\UNC\`, with the "server" and "share" components following it. + /// Verbatim prefix using Windows' _**U**niform **N**aming **C**onvention_, + /// e.g. `\\?\UNC\server\share`. + /// + /// Verbatim UNC prefixes consist of `\\?\UNC\` immediately followed by the + /// server's hostname and a share name. #[stable(feature = "rust1", since = "1.0.0")] VerbatimUNC( #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, ), - /// Prefix like `\\?\C:\`, for the given drive letter + /// Verbatim disk prefix, e.g. `\\?\C:\`. + /// + /// Verbatim disk prefixes consist of `\\?\` immediately followed by the + /// drive letter and `:\`. #[stable(feature = "rust1", since = "1.0.0")] VerbatimDisk(#[stable(feature = "rust1", since = "1.0.0")] u8), - /// Prefix `\\.\`, together with the given component immediately following it. + /// Device namespace prefix, e.g. `\\.\COM42`. + /// + /// Device namespace prefixes consist of `\\.\` immediately followed by the + /// device name. #[stable(feature = "rust1", since = "1.0.0")] DeviceNS(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), - /// Prefix `\\server\share`, with the given "server" and "share" components. + /// Prefix using Windows' _**U**niform **N**aming **C**onvention_, e.g. + /// `\\server\share`. + /// + /// UNC prefixes consist of the server's hostname and a share name. #[stable(feature = "rust1", since = "1.0.0")] UNC( #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, @@ -217,6 +218,20 @@ impl<'a> Prefix<'a> { } /// Determines if the prefix is verbatim, i.e. begins with `\\?\`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Prefix::*; + /// use std::ffi::OsStr; + /// + /// assert!(Verbatim(OsStr::new("pictures")).is_verbatim()); + /// assert!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")).is_verbatim()); + /// assert!(VerbatimDisk('C' as u8).is_verbatim()); + /// assert!(!DeviceNS(OsStr::new("BrainInterface")).is_verbatim()); + /// assert!(!UNC(OsStr::new("server"), OsStr::new("share")).is_verbatim()); + /// assert!(!Disk('C' as u8).is_verbatim()); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_verbatim(&self) -> bool { @@ -356,9 +371,42 @@ enum State { Done = 3, } -/// A Windows path prefix, e.g. `C:` or `\\server\share`. +/// A structure wrapping a Windows path prefix as well as its unparsed string +/// representation. +/// +/// In addition to the parsed [`Prefix`] information returned by [`kind`], +/// `PrefixComponent` also holds the raw and unparsed [`OsStr`] slice, +/// returned by [`as_os_str`]. +/// +/// Instances of this `struct` can be obtained by matching against the +/// [`Prefix` variant] on [`Component`]. /// /// Does not occur on Unix. +/// +/// # Examples +/// +/// ``` +/// # if cfg!(windows) { +/// use std::path::{Component, Path, Prefix}; +/// use std::ffi::OsStr; +/// +/// let path = Path::new(r"c:\you\later\"); +/// match path.components().next().unwrap() { +/// Component::Prefix(prefix_component) => { +/// assert_eq!(Prefix::Disk('C' as u8), prefix_component.kind()); +/// assert_eq!(OsStr::new("c:"), prefix_component.as_os_str()); +/// } +/// _ => unreachable!(), +/// } +/// # } +/// ``` +/// +/// [`as_os_str`]: #method.as_os_str +/// [`Component`]: enum.Component.html +/// [`kind`]: #method.kind +/// [`OsStr`]: ../../std/ffi/struct.OsStr.html +/// [`Prefix` variant]: enum.Component.html#variant.Prefix +/// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Eq, Debug)] pub struct PrefixComponent<'a> { @@ -370,13 +418,20 @@ pub struct PrefixComponent<'a> { } impl<'a> PrefixComponent<'a> { - /// The parsed prefix data. + /// Returns the parsed prefix data. + /// + /// See [`Prefix`]'s documentation for more information on the different + /// kinds of prefixes. + /// + /// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] pub fn kind(&self) -> Prefix<'a> { self.parsed } - /// The raw `OsStr` slice for this prefix. + /// Returns the raw [`OsStr`] slice for this prefix. + /// + /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(&self) -> &'a OsStr { self.raw @@ -413,11 +468,11 @@ impl<'a> Hash for PrefixComponent<'a> { /// A single component of a path. /// -/// See the module documentation for an in-depth explanation of components and -/// their role in the API. +/// A `Component` roughtly corresponds to a substring between path separators +/// (`/` or `\`). /// -/// This `enum` is created from iterating over the [`path::Components`] -/// `struct`. +/// This `enum` is created by iterating over [`Components`], which in turn is +/// created by the [`components`][`Path::components`] method on [`Path`]. /// /// # Examples /// @@ -434,37 +489,49 @@ impl<'a> Hash for PrefixComponent<'a> { /// ]); /// ``` /// -/// [`path::Components`]: struct.Components.html +/// [`Components`]: struct.Components.html +/// [`Path`]: struct.Path.html +/// [`Path::components`]: struct.Path.html#method.components #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Component<'a> { /// A Windows path prefix, e.g. `C:` or `\\server\share`. /// + /// There is a large variety of prefix types, see [`Prefix`]'s documentation + /// for more. + /// /// Does not occur on Unix. + /// + /// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] Prefix( #[stable(feature = "rust1", since = "1.0.0")] PrefixComponent<'a> ), - /// The root directory component, appears after any prefix and before anything else + /// The root directory component, appears after any prefix and before anything else. + /// + /// It represents a separator that designates that a path starts from root. #[stable(feature = "rust1", since = "1.0.0")] RootDir, - /// A reference to the current directory, i.e. `.` + /// A reference to the current directory, i.e. `.`. #[stable(feature = "rust1", since = "1.0.0")] CurDir, - /// A reference to the parent directory, i.e. `..` + /// A reference to the parent directory, i.e. `..`. #[stable(feature = "rust1", since = "1.0.0")] ParentDir, - /// A normal component, i.e. `a` and `b` in `a/b` + /// A normal component, e.g. `a` and `b` in `a/b`. + /// + /// This variant is the most common one, it represents references to files + /// or directories. #[stable(feature = "rust1", since = "1.0.0")] Normal(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), } impl<'a> Component<'a> { - /// Extracts the underlying `OsStr` slice. + /// Extracts the underlying [`OsStr`] slice. /// /// # Examples /// @@ -475,6 +542,8 @@ impl<'a> Component<'a> { /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect(); /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]); /// ``` + /// + /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(self) -> &'a OsStr { match self { @@ -494,12 +563,10 @@ impl<'a> AsRef for Component<'a> { } } -/// The core iterator giving the components of a path. -/// -/// See the module documentation for an in-depth explanation of components and -/// their role in the API. +/// An interator over the [`Component`]s of a [`Path`]. /// -/// This `struct` is created by the [`path::Path::components`] method. +/// This `struct` is created by the [`components`] method on [`Path`]. +/// See its documentation for more. /// /// # Examples /// @@ -513,7 +580,9 @@ impl<'a> AsRef for Component<'a> { /// } /// ``` /// -/// [`path::Path::components`]: struct.Path.html#method.components +/// [`Component`]: enum.Component.html +/// [`components`]: struct.Path.html#method.components +/// [`Path`]: struct.Path.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Components<'a> { @@ -534,9 +603,15 @@ pub struct Components<'a> { back: State, } -/// An iterator over the components of a path, as [`OsStr`] slices. +/// An iterator over the [`Component`]s of a [`Path`], as [`OsStr`] slices. /// +/// This `struct` is created by the [`iter`] method on [`Path`]. +/// See its documentation for more. +/// +/// [`Component`]: enum.Component.html +/// [`iter`]: struct.Path.html#method.iter /// [`OsStr`]: ../../std/ffi/struct.OsStr.html +/// [`Path`]: struct.Path.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a> { @@ -762,6 +837,18 @@ impl<'a> fmt::Debug for Iter<'a> { impl<'a> Iter<'a> { /// Extracts a slice corresponding to the portion of the path remaining for iteration. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let mut iter = Path::new("/tmp/foo/bar.txt").iter(); + /// iter.next(); + /// iter.next(); + /// + /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &'a Path { self.inner.as_path() @@ -1067,9 +1154,10 @@ impl PathBuf { /// Truncate `self` to [`self.parent`]. /// - /// Returns false and does nothing if [`self.file_name`] is `None`. + /// Returns `false` and does nothing if [`self.file_name`] is [`None`]. /// Otherwise, returns `true`. /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`self.parent`]: struct.PathBuf.html#method.parent /// [`self.file_name`]: struct.PathBuf.html#method.file_name /// @@ -1132,10 +1220,11 @@ impl PathBuf { /// Updates [`self.extension`] to `extension`. /// - /// If [`self.file_name`] is `None`, does nothing and returns `false`. + /// Returns `false` and does nothing if [`self.file_name`] is [`None`], + /// returns `true` and updates the extension otherwise. /// - /// Otherwise, returns `true`; if [`self.extension`] is [`None`], the - /// extension is added; otherwise it is replaced. + /// If [`self.extension`] is [`None`], the extension is added; otherwise + /// it is replaced. /// /// [`self.file_name`]: struct.PathBuf.html#method.file_name /// [`self.extension`]: struct.PathBuf.html#method.extension @@ -1195,7 +1284,10 @@ impl PathBuf { self.inner } - /// Converts this `PathBuf` into a boxed `Path`. + /// Converts this `PathBuf` into a [boxed][`Box`] [`Path`]. + /// + /// [`Box`]: ../../std/boxed/struct.Box.html + /// [`Path`]: struct.Path.html #[unstable(feature = "into_boxed_path", issue = "40380")] pub fn into_boxed_path(self) -> Box { unsafe { mem::transmute(self.inner.into_boxed_os_str()) } @@ -1402,10 +1494,14 @@ pub struct Path { inner: OsStr, } -/// An error returned from the [`Path::strip_prefix`] method indicating that the -/// prefix was not found in `self`. +/// An error returned from [`Path::strip_prefix`][`strip_prefix`] if the prefix +/// was not found. +/// +/// This `struct` is created by the [`strip_prefix`] method on [`Path`]. +/// See its documentation for more. /// -/// [`Path::strip_prefix`]: struct.Path.html#method.strip_prefix +/// [`strip_prefix`]: struct.Path.html#method.strip_prefix +/// [`Path`]: struct.Path.html #[derive(Debug, Clone, PartialEq, Eq)] #[stable(since = "1.7.0", feature = "strip_prefix")] pub struct StripPrefixError(()); @@ -1421,7 +1517,7 @@ impl Path { os_str_as_u8_slice(&self.inner) } - /// Directly wrap a string slice as a `Path` slice. + /// Directly wraps a string slice as a `Path` slice. /// /// This is a cost-free conversion. /// @@ -1525,10 +1621,11 @@ impl Path { PathBuf::from(self.inner.to_os_string()) } - /// A path is *absolute* if it is independent of the current directory. + /// Returns `true` if the `Path` is absolute, i.e. if it is independent of + /// the current directory. /// /// * On Unix, a path is absolute if it starts with the root, so - /// `is_absolute` and `has_root` are equivalent. + /// `is_absolute` and [`has_root`] are equivalent. /// /// * On Windows, a path is absolute if it has a prefix and starts with the /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not. @@ -1540,6 +1637,8 @@ impl Path { /// /// assert!(!Path::new("foo.txt").is_absolute()); /// ``` + /// + /// [`has_root`]: #method.has_root #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] pub fn is_absolute(&self) -> bool { @@ -1547,7 +1646,9 @@ impl Path { self.has_root() && (cfg!(unix) || cfg!(target_os = "redox") || self.prefix().is_some()) } - /// A path is *relative* if it is not absolute. + /// Return `false` if the `Path` is relative, i.e. not absolute. + /// + /// See [`is_absolute`]'s documentation for more details. /// /// # Examples /// @@ -1556,6 +1657,8 @@ impl Path { /// /// assert!(Path::new("foo.txt").is_relative()); /// ``` + /// + /// [`is_absolute`]: #method.is_absolute #[stable(feature = "rust1", since = "1.0.0")] pub fn is_relative(&self) -> bool { !self.is_absolute() @@ -1565,7 +1668,7 @@ impl Path { self.components().prefix } - /// A path has a root if the body of the path begins with the directory separator. + /// Returns `true` if the `Path` has a root. /// /// * On Unix, a path has a root if it begins with `/`. /// @@ -1586,7 +1689,7 @@ impl Path { self.components().has_root() } - /// The path without its final component, if any. + /// Returns the `Path` without its final component, if there is one. /// /// Returns [`None`] if the path terminates in a root or prefix. /// @@ -1619,9 +1722,9 @@ impl Path { }) } - /// The final component of the path, if it is a normal file. + /// Returns the final component of the `Path`, if it is a normal file. /// - /// If the path terminates in `..`, `file_name` will return [`None`]. + /// Returns [`None`] If the path terminates in `..`. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None /// @@ -1631,18 +1734,7 @@ impl Path { /// use std::path::Path; /// use std::ffi::OsStr; /// - /// let path = Path::new("foo.txt"); - /// let os_str = OsStr::new("foo.txt"); - /// - /// assert_eq!(Some(os_str), path.file_name()); - /// ``` - /// - /// # Other examples - /// - /// ``` - /// use std::path::Path; - /// use std::ffi::OsStr; - /// + /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt").file_name()); /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name()); /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name()); /// assert_eq!(None, Path::new("foo.txt/..").file_name()); @@ -1869,7 +1961,21 @@ impl Path { buf } - /// Produce an iterator over the components of the path. + /// Produces an iterator over the [`Component`]s of the path. + /// + /// When parsing the path, there is a small amount of normalization: + /// + /// * Repeated separators are ignored, so `a/b` and `a//b` both have + /// `a` and `b` as components. + /// + /// * Occurentces of `.` are normalized away, exept if they are at the + /// beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and + /// `a/b` all have `a` and `b` as components, but `./a/b` starts with + /// an additional [`CurDir`] component. + /// + /// Note that no other normalization takes place; in particular, `a/c` + /// and `a/b/../c` are distinct, to account for the possibility that `b` + /// is a symbolic link (so its parent isn't `a`). /// /// # Examples /// @@ -1884,6 +1990,9 @@ impl Path { /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt")))); /// assert_eq!(components.next(), None) /// ``` + /// + /// [`Component`]: enum.Component.html + /// [`CurDir`]: enum.Component.html#variant.CurDir #[stable(feature = "rust1", since = "1.0.0")] pub fn components(&self) -> Components { let prefix = parse_prefix(self.as_os_str()); @@ -1896,8 +2005,13 @@ impl Path { } } - /// Produce an iterator over the path's components viewed as [`OsStr`] slices. + /// Produces an iterator over the path's components viewed as [`OsStr`] + /// slices. + /// + /// For more information about the particulars of how the path is separated + /// into components, see [`components`]. /// + /// [`components`]: #method.components /// [`OsStr`]: ../ffi/struct.OsStr.html /// /// # Examples @@ -1936,7 +2050,7 @@ impl Path { Display { path: self } } - /// Query the file system to get information about a file, directory, etc. + /// Queries the file system to get information about a file, directory, etc. /// /// This function will traverse symbolic links to query information about the /// destination file. @@ -1959,7 +2073,7 @@ impl Path { fs::metadata(self) } - /// Query the metadata about a file without following symlinks. + /// Queries the metadata about a file without following symlinks. /// /// This is an alias to [`fs::symlink_metadata`]. /// @@ -2096,7 +2210,11 @@ impl Path { fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) } - /// Converts a `Box` into a `PathBuf` without copying or allocating. + /// Converts a [`Box`][`Box`] into a [`PathBuf`] without copying or + /// allocating. + /// + /// [`Box`]: ../../std/boxed/struct.Box.html + /// [`PathBuf`]: struct.PathBuf.html #[unstable(feature = "into_boxed_path", issue = "40380")] pub fn into_path_buf(self: Box) -> PathBuf { let inner: Box = unsafe { mem::transmute(self) }; @@ -2118,7 +2236,26 @@ impl fmt::Debug for Path { } } -/// Helper struct for safely printing paths with `format!()` and `{}` +/// Helper struct for safely printing paths with [`format!`] and `{}`. +/// +/// A [`Path`] might contain non-Unicode data. This `struct` implements the +/// [`Display`] trait in a way that mitigates that. It is created by the +/// [`display`][`Path::display`] method on [`Path`]. +/// +/// # Examples +/// +/// ``` +/// use std::path::Path; +/// +/// let path = Path::new("/tmp/foo.rs"); +/// +/// println!("{}", path.display()); +/// ``` +/// +/// [`Display`]: ../../std/fmt/trait.Display.html +/// [`format!`]: ../../std/macro.format.html +/// [`Path`]: struct.Path.html +/// [`Path::display`]: struct.Path.html#method.display #[stable(feature = "rust1", since = "1.0.0")] pub struct Display<'a> { path: &'a Path, diff --git a/src/test/run-pass/issue-41298.rs b/src/test/run-pass/issue-41298.rs new file mode 100644 index 0000000000000..2b9baa746748b --- /dev/null +++ b/src/test/run-pass/issue-41298.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Function { t: T, f: F } + +impl Function R> { fn foo() { } } +impl Function R> { fn bar() { } } + +fn main() { } diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index c7113edbf9e68..012ee835494e8 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -22,12 +22,6 @@ struct Test { } const TEST_REPOS: &'static [Test] = &[ - Test { - name: "cargo", - repo: "https://github.com/rust-lang/cargo", - sha: "0e1e34be7540bdaed4918457654fbf028cf69e56", - lock: None, - }, Test { name: "iron", repo: "https://github.com/iron/iron", @@ -61,20 +55,6 @@ const TEST_REPOS: &'static [Test] = &[ ]; fn main() { - // One of the projects being tested here is Cargo, and when being tested - // Cargo will at some point call `nmake.exe` on Windows MSVC. Unfortunately - // `nmake` will read these two environment variables below and try to - // intepret them. We're likely being run, however, from MSYS `make` which - // uses the same variables. - // - // As a result, to prevent confusion and errors, we remove these variables - // from our environment to prevent passing MSYS make flags to nmake, causing - // it to blow up. - if cfg!(target_env = "msvc") { - env::remove_var("MAKE"); - env::remove_var("MAKEFLAGS"); - } - let args = env::args().collect::>(); let ref cargo = args[1]; let out_dir = Path::new(&args[2]); diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index d5b95c08306b2..e320933067226 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -8,5 +8,5 @@ license = "MIT/Apache-2.0" clap = "2.19.3" [dependencies.mdbook] -version = "0.0.18" +version = "0.0.19" default-features = false